Netch
Netch

Reputation: 4582

Vertex shader does not apply second attribute array

Consider a simple game with two classes of objects (ball and wall). Tutorials I've found suggests using a single vertex data array in the manner like:

[... initializing ...]

vdata = new float[ENOUGH_FOR_ALL];
vertexData = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
aPositionLocation = glGetAttribLocation(programId, "a_Position");
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 0, vertexData);
glEnableVertexAttribArray(aPositionLocation);

[...drawing...]

vertexData.position(0);
vertexData.put(vdata);
glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f); // ball is red
glDrawArrays(GL_TRIANGLE_FAN, 0, BALL_VERTICES + 2);
glUniform4f(uColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); // wall is green
glDrawArrays(GL_LINES, BALL_VERTICES + 2, 2); // wall as a single line

and, the vertex shader is trivial:

attribute vec4 a_Position;

void main() {
    gl_Position = a_Position;
}

This works but requires cumbersome calculation of offsets in a single buffer, moving when some object size changes...

Consider the following vertex shader

attribute vec4 a_Ball;
attribute vec4 a_Wall;
uniform float u_WhatDraw;

void main() {
    if (u_WhatDraw == 1.0) {
        gl_Position = a_Ball;
    }
    else if (u_WhatDraw == 2.0) {
        gl_Position = a_Wall;
    }
}

data prepared as:

ball_data = new float[BALL_VERTICES + 2];
wall_data = new float[4]; // a single line
ballVertexData = ByteBuffer.allocateDirect(ball_data.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
wallVertexData = ByteBuffer.allocateDirect(wall_data.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
aBallLocation = glGetAttribLocation(programId, "a_Ball");
glVertexAttribPointer(aBallLocation, 2, GL_FLOAT, false, 0, ballVertexData);
glEnableVertexAttribArray(aBallLocation);
aWallLocation = glGetAttribLocation(programId, "a_Wall");
glVertexAttribPointer(aWallLocation, 2, GL_FLOAT, false, 0, wallVertexData);
glEnableVertexAttribArray(aWallLocation);

[...generation of static wall_data skipped...]

[...drawing...]

ballVertexData.position(0);
ballVertexData.put(ball_data);
glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f); // ball is red
glUniform1f(uWhatDrawLocation, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, BALL_VERTICES + 2);
glUniform4f(uColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); // wall is green
glUniform1f(uWhatDrawLocation, 2.0f);
glDrawArrays(GL_LINES, 0, 2); // wall as a single line

This does not draw wall at all, despite the ball is drawn.

Please suggest in fixing this with 2-array approach or explain a limitation why I should stick with a single array for all activity.

Upvotes: 0

Views: 32

Answers (1)

solidpixel
solidpixel

Reputation: 12229

This works but requires cumbersome calculation of offsets in a single buffer, moving when some object size changes...

If object size changes you need to reupload new mesh data, so computing offsets seems to be the least of the problems.

or explain a limitation why I should stick with a single array for all activity.

What happens when you add a third object, or a fourth, or a fifth?

You're optimizing the wrong problem.

Any time you are required to generate shaders with if (<insert uniform>) ... you're doing it wrong - never make the GPU make control plane decisions for every vertex when the application can just do it once.

Upvotes: 1

Related Questions