Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use a shader to colour lines drawn with GL_LINES and OpenGL ES 2.0

I have an Android app using OpenGL ES 2.0. I need to draw 10 lines from an array each of which are described by a start point and an end point. So there are 10 lines = 20 points = 60 floats values. None of the points are connected so each pair of points in the array is unrelated to the others, hence I draw with GL_LINES.

I draw them by putting the values into a float buffer and calling some helper code like this:

public void drawLines(FloatBuffer vertexBuffer, float lineWidth,
        int numPoints, float colour[]) {
    GLES20.glLineWidth(lineWidth);
    drawShape(vertexBuffer, GLES20.GL_LINES, numPoints, colour);
}

protected void drawShape(FloatBuffer vertexBuffer, int drawType,
        int numPoints, float colour[]) {
    // ... set shader ...
    GLES20.glDrawArrays(drawType, 0, numPoints);
}

The drawLines takes the float buffer (60 floats), a linewidth, the number of points (20) and a 4 float colour value array. I haven't shown the shader setting code but it basically exposes the colour variable to uniform uColour value.

The fragment shader that picks up uColour just plugs it straight into the output.

/* Fragment */
precision mediump float;

uniform vec4 uColour;
uniform float uTime;

void main() {
    gl_FragColor = uColour;
}

The vertex shader:

uniform mat4 uMVPMatrix;

attribute vec4 vPosition;

void main() {
    gl_Position = uMVPMatrix * vPosition;
}

But now I want to do something different. I want every line in my buffer to have a different colour. The colours are a function of the position of the line in the array. I want to shade the beginning line white, the last dark gray and lines between a gradation between the two, e.g. #ffffff, #eeeeee, #dddddd etc.

I could obviously just draw each line individually plugging a new value into uColour each time but that is inefficient. I don't want to call GL 10 times when I could call it once and modify the value in a shader each time around.

Perhaps I could declare a uniform value called uVertexCount in my vertex shader? Prior to the draw I set uVertexCount to 0 and for each time the vertex shader is called I increment this value. The fragment shader could determine the line index by looking at uVertexCount. It could then interpolate a value for the colour between some start and end value or some other means. But this depends if every line or point is considered a primitive or the whole array of lines is a single primitive.

Is this feasible? I don't know how many times the vertex shader is called per fragment shader. Are the calls interleaved in a way such as this to make it viable, i.e. vertex 0, vertex 1, x * fragment, vertex 2, vertex 3, x * fragment etc.

Does anyone know of some reasonable sample code that might demonstrate the concept or point me to some other way of doing something similar?

like image 919
locka Avatar asked May 23 '12 12:05

locka


People also ask

How do shaders work in OpenGL?

A Shader is a user-defined program designed to run on some stage of a graphics processor. Shaders provide the code for certain programmable stages of the rendering pipeline. They can also be used in a slightly more limited form for general, on-GPU computation.

How does a geometry shader work?

A geometry shader takes as input a set of vertices that form a single primitive e.g. a point or a triangle. The geometry shader can then transform these vertices as it sees fit before sending them to the next shader stage.

What shader language does OpenGL use?

The OpenGL Shading Language (GLSL) is the principal shading language for OpenGL. While, thanks to OpenGL Extensions, there are several shading languages available for use in OpenGL, GLSL (and SPIR-V) are supported directly by OpenGL without extensions. GLSL is a C-style language.


1 Answers

Add color information into your Vertexbuffer (Floatbuffer) and use the attribute in your shader.

Example vertexbuffer:

uniform mat4 uMVPMatrix;

attribute vec4 vPosition;
attribute vec3 vColor;

varying vec3 color;

void main() {
    gl_Position = uMVPMatrix * vPosition;
    color = vColor;
}

Example fragmentshader:

precision mediump float;

varying vec3 color;

void main() {
    gl_FragColor = color;
}
like image 174
pearcoding Avatar answered Oct 14 '22 01:10

pearcoding