2
\$\begingroup\$

It was supposed to be a continuous tube, made out of 5000 instanced rings of 60 cubes each (12 triangles each) on my integrated laptop intel GPU card using OpenGL 3.3. Bad Tube

That was what I got. The distortions you see can also be seen when rendering 1000 or 500 rings, albeit at much lower quantity and severity.

What is causing it? I've disabled polygon smoothing, and it helped immensely, but didn't eliminate the problem. I've also found out that vertex shader variables are highp by default. There is no front culling either.

Here it is how it is supposed to look (same rendering, but from front, where it is not distorted).

Good Tube

The FPS is about 10. NearZ is 0.01, FarZ is 100, also tried 1..1000, didn't change much, if anything.

Can this possibly be just because I render too many triangles and the solution would be to make less of them?

Shader codes:

const char *VERT_SRC_FSTR =
"#version 330 core\n"
"in vec3 pos;\n"
"flat out int vertexID, instanceID;\n"
"uniform vec3 mov[%d], eye;\n" // %d - RENDERER_MAX_INSTANCE_COUNT
"uniform mat4 proj, view;\n"
"void main(void)\n{\n"
"    vertexID = gl_VertexID;\n"
"    instanceID = gl_InstanceID;\n"
"    vec4 p = proj * view * vec4(pos - eye + mov[gl_InstanceID], 1);\n"
"    p.x *= %f;\n" // %f - inversed aspection ratio (9/16)
"    gl_Position = p;\n}\n";
const char *FRAG_SRC_FSTR =
"#version 330 core\n"
"flat in int vertexID, instanceID;\n"
"out vec3 clr;\n"
"void main(void)\n{\n"
"    clr = vec3(vertexID %% 2, 1, instanceID %% 2);\n}\n";

Is there anything else I can try? Could this be an issue with my driver/graphics card?

Edit: glxinfo excerpt:

Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Intel Open Source Technology Center (0x8086)
    Device: Mesa DRI Intel(R) Bay Trail  (0xf31)
    Version: 12.0.6
    Accelerated: yes
    Video memory: 1536MB
    Unified memory: yes
    Preferred profile: core (0x1)
    Max core profile version: 3.3
    Max compat profile version: 3.0
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.0
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) Bay Trail 
OpenGL core profile version string: 3.3 (Core Profile) Mesa 12.0.6
OpenGL core profile shading language version string: 3.30
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile

Rendering code:

// Rendering draw function:
void rendererDraw(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glUniform3fv(renderer.eyeLoc, 1, rendererInput.eye);
    glUniformMatrix4fv(renderer.projLoc, 1, GL_FALSE, rendererInput.proj);
    glUniformMatrix4fv(renderer.viewLoc, 1, GL_FALSE, rendererInput.view);
    for (struct RendererDrawable *d = rendererInput.drawables; d->vao!=0; ++d)
    {
        glUniform3fv(renderer.movLoc, d->instanceCount, d->mov);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glBindVertexArray(d->vao);
        glDrawArraysInstanced(d->drawMode, 0, d->pointCount, d->instanceCount);
        glfwSwapBuffers(win);
    }
    glfwSwapBuffers(win);
}

Renderer header:

// Renderer public data:
extern struct RendererInput
{
    Vector eye;
    Matrix proj, view;
    struct RendererDrawable *drawables; // terminated by (drawable->vao == 0)
} rendererInput;

extern struct RendererOutput
{
    GLint posLoc;
} rendererOutput;

struct RendererDrawable
{
    GLenum drawMode;
    GLuint vao, pointCount, instanceCount;
    Vector *mov;
};

Drawable setup in engine.c:

void engineInit(void)
{
    rendererInput.drawables = calloc(2, sizeof(*rendererInput.drawables));
    // rendererInput.drawables[0] - the RING, which is being
    // drawn instanced multiple times with different offset (mov)
    rendererInput.drawables[0] = drawableCubeCircle();
    rendererInput.drawables[0].instanceCount = RENDERER_MAX_INSTANCE_COUNT;
    rendererInput.drawables[0].mov[0][0] = 0;
    rendererInput.drawables[0].mov[0][1] = 0;
    for (int i = 0; i < RENDERER_MAX_INSTANCE_COUNT; ++i) rendererInput.drawables[0].mov[i][2] = i;
    cameraInit();
    timerFrameReset();
}

A single ring being renderered correctly:

Ring

The issue here is not the ring itself, but their "chaining". As you can see in the pictures, most of the time it works correctly, but sometimes there are distortions. Since I'm not generating a mesh and instantiating them instead, the problem could only lie within:

for (int i = 0; i < RENDERER_MAX_INSTANCE_COUNT; ++i) rendererInput.drawables[0].mov[i][2] = i;

but I don't see it there.

\$\endgroup\$
  • \$\begingroup\$ My advice: Try it on a different OpenGL driver by a different GPU brand then make your own conclusions... \$\endgroup\$ – Stephane Hockenhull Feb 18 '17 at 1:19
  • \$\begingroup\$ While not directly linked to your question, I wanted to suggest that you look into combining your rings together into single meshes, thus reducing the draw calls and total triangles being rendered. You could turn the entire side of that ring into only two triangles, instead of a million. \$\endgroup\$ – Krythic Feb 18 '17 at 2:01
  • \$\begingroup\$ Also, can we see the way that you're generating these rings? there could be some sort of rounding error taking place. \$\endgroup\$ – Krythic Feb 18 '17 at 2:03
  • \$\begingroup\$ In the game the pipe will be infinite and you will be traveling through it at a very high speed. The rings past you will be immediately moved to the back of the infinite pipe. What I can do, and am currently working on, is improving the rings themselves, eliminating walls that you can't see from the inside and using indexing. \$\endgroup\$ – Marius Macijauskas Feb 18 '17 at 2:05
  • \$\begingroup\$ Welcome to GDSE! Here,if you actually find an answer to your won question, you should write an answer and mark it as accepted instead of adding it to the question post, and renaming the title to 'solved'. You can write an answer to your own question, and mark is as accepted, it's a perfectly acceptable behaviour here :) And in fact, it is what's expected! \$\endgroup\$ – Vaillancourt Feb 18 '17 at 3:00
4
\$\begingroup\$

I forgot to initialize other offset vector array fields (x and y), leaving them undefined.

Before:

void engineInit(void)
{
    rendererInput.drawables = calloc(2, sizeof(*rendererInput.drawables));
    rendererInput.drawables[0] = drawableCubeCircle();
    rendererInput.drawables[0].instanceCount = RENDERER_MAX_INSTANCE_COUNT;
    rendererInput.drawables[0].mov[0][0] = 0; // <--- all other values undefined
    rendererInput.drawables[0].mov[0][1] = 0; // <--- all other values undefined
    for (int i = 0; i < RENDERER_MAX_INSTANCE_COUNT; ++i)
    {
        rendererInput.drawables[0].mov[i][2] = i;
    }
    cameraInit();
    timerFrameReset();
}

Fixed:

void engineInit(void)
{
    rendererInput.drawables = calloc(2, sizeof(*rendererInput.drawables));
    rendererInput.drawables[0] = drawableCubeCircle();
    rendererInput.drawables[0].instanceCount = RENDERER_MAX_INSTANCE_COUNT;
    for (int i = 0; i < RENDERER_MAX_INSTANCE_COUNT; ++i)
    {
        rendererInput.drawables[0].mov[i][0] = 0; // <--- fixed
        rendererInput.drawables[0].mov[i][1] = 0; // <--- fixed
        rendererInput.drawables[0].mov[i][2] = i;
    }
    cameraInit();
    timerFrameReset();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.