0
\$\begingroup\$

I'm developing a game (in Ogre3D) that, in short, consist in a vehicle that moves along a terrain and leaves a colored trail behind it. The trails are basically quads (a), these quads changes their color accordingly to the vehicle's speed. My challenge now is that I need to subdivide these quads into 5 (or more) sub-polygons (b) and each one of them should have a different color accordingly to others vehicle's properties. When moving around for a while these quads start to accumulate on screen and the render process starts to heavily lag and thus fps count is sub optimal. quads

Some considerations: - All quads are appended to a single mesh that belongs to a single entity sharing the same material, so batching should be optimal. - Tried adding LOD for this mesh but I had no luck to make it work in Ogre1.9.

So, my main question is how can I optimize the rendering of this polygons?? Can I delegate this task by somehow to the gpu via shader programming?

Edit: My goal would be to avoid having to draw each one of those sub-quads in (b) (only draw the big quad (a)) but by somehow being able to colorize each one of those sub-quads.

\$\endgroup\$
3
  • \$\begingroup\$ culling (filler) \$\endgroup\$
    – Bálint
    Commented Apr 10, 2018 at 18:48
  • \$\begingroup\$ It can be done with shaders, you would attach properties to the vertex of your quads to specify whatever properties you need to compute the colors on the GPU. if I were you, I would put a limit on the lenght of the trail and have it fade away (in fact, if you want, you can animate alpha in GPU, pass the time as a u̶n̶i̶f̶o̶r̶m̶ global variable to the shader. Edit: assuming you have all you need for alpha blending/transparency already working), and that way keep the polygon count in check. For what I read Ogre uses HLSL, I am only familiar with GLSL (at least, so far). \$\endgroup\$
    – Theraot
    Commented Apr 10, 2018 at 18:58
  • \$\begingroup\$ AFAIK Ogre uses both GLSL(ES) and HLSL. You suggest that the only data needed by the shaders would be: (vertex)v0, v1, v2, v3, (double) prop1, prop2...propN (for coloring each sub-quad) ? How can I specify the coordinates of each sub-quad (uv coord?)?. @Bálint could you please clarify your idea? \$\endgroup\$
    – EzeEst
    Commented Apr 10, 2018 at 19:42

2 Answers 2

1
\$\begingroup\$

NOTE: I am unfamiliar with Ogre3d but I do greatly enjoy optimizing things.

I would imagine that part of the issue is that you're going to be continually Allocating memory. What's worse, it sounds like you're appending this allocated memory to a structure you already have. What can happen is that as these accumulate you may be rewriting the structure as you append to it. If you're using a C# List, a C++ Vector, or many other datastructures, you could instead be requesting it allocate a contiguous block of size equal to double your current size, which will slowly cause it to fragment your memory and allocated giant chunks. Definitely look into how you're allocating your memory for this, and really consider how badly you need these to be truly a single mesh rather than simply adjacent to one another.

Secondly, it sounds as though you're trying to solve your problem with more Polygons when you don't need them. For instance, if you wrote a shader that took those properties and simply colored the original polygon in sections according to the data you want, you could easy save yourself the quin-tupling of quads you're experiencing.

Lastly, it also sounds as though you're possibly "rendering" things that aren't on screen, when this is unnecessary. If these things exist as a way to see the history of how your vehicle traveled, you can simply care about the ones that are in view. Be sure you're only rendering those that are on screen.

Without code I'm not sure there's anything else I could suggest. Hope this helps!

\$\endgroup\$
2
  • \$\begingroup\$ I'm not using an "external" container to allocate the vertex data, in fact I'm using: mMyMesh->getSubMesh[0]->addTriangle(<newTri>) to add a new triangle to mMyMesh. The shader approach sounds quite good (having N-less polygons is very tempting). I'm (almost) sure that Ogre is culling the quads that are outside my camera: if I zoom in into the vehicle (few quads visible) fps > 60 but zooming out enough so I can see many of the other old quads fps < 10. Any snippet or guideline to code these shaders? \$\endgroup\$
    – EzeEst
    Commented Apr 10, 2018 at 19:57
  • \$\begingroup\$ The main guideline would be that you should make it modular. In psuedo-code it may look like pixelWidth = quadwidth / parameters.length; for index, param in parameters: Color(Rect(index*pixelWidth, 0, (index+1)*pixelWidth,quadHeight), param.GetColor()); This would allow you to do 2, 5, or 17 params; without updating the code later. I'd also say that there's a reasonable chance that addTriangle is talking to a data structure that can grow, and is allocating new vertices as it goes. You can speed this up by using an Object Pool or pre-allocating them in other ways \$\endgroup\$
    – blurry
    Commented Apr 10, 2018 at 21:43
0
\$\begingroup\$

Disclaimer: I am not familiar with Ogre3D.

You can manage to do the effect you want via shaders.

Since I am only familiar with GLSL I will be using that...

First off all, whatever changes from quad to quad (for example the speed of the vehicle) you need to pass it as an attribute. I will assume we pass four such properties (based on the example image) and they dictate the intensity of the colors of the bands.

Note: I say quad, but there is no difference if you are using triangle primitives. I fact I tested this with triangles.

Now, how does the shader knows the positions to place those colors? Well, you need to pass an additional attribute for that. Sure, it can be standard texture coordinates, but it does not need to be. It makes no difference.

With that said, our vextex shader will be doing passthrough, so we can use the properties in the fragment shader:

#version 330

layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in float prop1;
layout (location = 2) in float prop2;
layout (location = 3) in float prop3;
layout (location = 4) in float prop4;
layout (location = 5) in float pos;

smooth out float vprop1;
smooth out float vprop2;
smooth out float vprop3;
smooth out float vprop4;
smooth out float vpos;

void main()
{
    vprop1 = prop1;
    vprop2 = prop2;
    vprop3 = prop3;
    vprop4 = prop4;
    vpos = pos;
    gl_Position = vec4(VertexPosition, 1.0f);
}

OpenGl will interpolate the values for us. Thus, if we pass pos=0 on one side of the quad and pos=1 on the other, we get a gradient. That is what we will be using that on the fragment shader to place the colors.

The other attributes (prop1, prop2, prop3, prop4) are going to tell the intensity of the colors. The code I wrote for that uses a vec4 to specify the color of each band and use scalar product.

Notice also that - with this shader code - OpenGL will also interpolate the values of the other attributes. This means that if you set the old values on the bottom of the quad and the new ones on the top you get a nice gradient.

This is the fragment shader I wrote for this:

#version 330

smooth in float vprop1;
smooth in float vprop2;
smooth in float vprop3;
smooth in float vprop4;
smooth in float vpos;

out vec4 FragColor;

void main()
{
    vec4 s =
          ((step(0.75, vpos) - step(1.00, vpos)) * vec4(0.0, 1.0, 1.0, 0.5) * vprop1)
        + ((step(0.50, vpos) - step(0.75, vpos)) * vec4(0.0, 0.0, 1.0, 0.5) * vprop2)
        + ((step(0.25, vpos) - step(0.50, vpos)) * vec4(0.0, 1.0, 0.0, 0.5) * vprop3)
        + ((step(0.00, vpos) - step(0.25, vpos)) * vec4(1.0, 1.0, 0.0, 0.5) * vprop4);
    FragColor = s;
}

Here the step function will give me hard edges for the colors. ((step(0.75, vpos) - step(1.00, vpos)) will be 1 when vpos is in the range from 0.75 to 1.00, and it will be 0 otherwise. Similarly happens with the other terms. Yes, I have extra zeroes after the comma, for readability.

The code above puts alpha on 0.5. Use whatever you need.


Aside from that, you are probably better off using an array to store your vertex, and use it as a circular buffer (once you get to the end, you start overwriting at the start). Using Triangles or Quads primitive type (but not strips or fans). Doing that you know it won't grow. I do not know how permisive Ogre3D is about that.

As, as I said, you can animate the quads fading away. You can add another attribute for the time when the quad was created, and pass the current time as a uniform to the shaders (Note: you do not need passthrough uniforms, you can use them directly in the fragment shader). That way the fragment shader knows how much time has passed since the Quad was created, and use that for setting alpha. Figure out what do you need to do on Ogre3D to get alpha blending working properly for the transparency effect.

\$\endgroup\$
4
  • \$\begingroup\$ I don't quite get why vpos is a float, shouldn't the step function by applied along quad's coords (gl_FragCoord) ? \$\endgroup\$
    – EzeEst
    Commented Apr 17, 2018 at 12:04
  • \$\begingroup\$ @EzeEst that would make the position of the colors relative to the screen, not the quad. \$\endgroup\$
    – Theraot
    Commented Apr 17, 2018 at 23:31
  • \$\begingroup\$ Trying to wrap my head around this, let's say that in Ogre I have a primitive to draw a triangle (that I call twice to draw a quad) addTriangle(v0,i0,v1,i1,v2,i2), I understand that calling the step function will only give color to the corresponding sub-quad; so, I should set the value of vpos let's say 4 times (one for each sub-quad) ? In short: how vpos will be "iterated" so each sub-quad can get its color? \$\endgroup\$
    – EzeEst
    Commented Apr 18, 2018 at 12:12
  • \$\begingroup\$ @EzeEst What you need to do is set the pos attribute to 0 on one side of the quad and 1 on the other. The vertex fragment I wrote expects a position (3 floats) then 4 properties (each float) and then that value that will be vpos (another float), PER VERTEX. If addTriangle does not allow you to have extra vertex attributes, then you need a different API. I believe this is how you do it in Orge: grahamedgecombe.com/blog/2011/08/05/custom-meshes-in-ogre3d - it appears Ogre calls element to the attributes. So no color element, but custom ones instead. Otherwise, reuse color and tex. \$\endgroup\$
    – Theraot
    Commented Apr 19, 2018 at 2:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .