int main(void)
{

My Blog

Posted 02/15/12 @ 5:13pm - By Ross

Dashed Lines!

So I recently have been playing around with shaders on my Android project and with the removal of stippling from the OpenGL I thought that I had found the perfect opportunity to use a shader. With some thoughts in mind I decided to search the interwebs to see if I was thinking along the right lines. Unfortunately there isn’t much out there on OpenGL ES 2.0 yet. So it fell to me to come up with something that would work, and work it does!

The basic premise was pretty simple. Find out the world coordinates of each fragment and then, using that, determine it’s length from the line origin. Then plug that into a cosine function and alternate drawing it based off if the value returned is negative or positive.

The key to the whole thing is sourcePoint being passed in as the origin of the line. It’s also worth noting that I pass in the modelview matrix and multiply it with the vertex to determine where it is in world space. The use of position as a varying variable is also important since it is interpolated based off all the vertices that affect it. This allows for the position variable in the fragment shader to be the actual position of the fragment in world space.

With all this, I determine the distance between those two points and then use the cosine function (modified based off how I want the dashes to look) to decide to draw it or not.

So without further ado, here is my vertex shader:

1
2
3
4
5
6
7
8
9
10
11
12
uniform mat4 u_modelViewProjectionMatrix;
uniform mat4 mv;
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;
varying vec4 position;

void main() {
  gl_Position = u_modelViewProjectionMatrix * a_position;
  position = mv * a_position;
  v_color = a_color;
}

and the fragment shader:

1
2
3
4
5
6
7
8
9
10
11
12
precision mediump float;
uniform vec2 sourcePoint;
varying vec4 v_color;
varying vec4 position;

void main() {
  if (cos(0.1*abs(distance(sourcePoint.xy, position.xy))) + 0.5 > 0.0) {
    gl_FragColor = vec4(0,0,0,0);
  } else {
    gl_FragColor = v_color;
  }
}
  • Mirza says:

    Hello I am trying the same you have done here and I have some problems. Can you please tell me what exactly is sourcePoint, mv and a_position? Thanks in advance

  • jiaqi says:

    My question is, what’s sourcePoint? Why it can be uniform? If I want to draw a dotted cube using this method, how can I set my sourcePoint? Thanks!

  • Victoria says:

    Thanks a lot for your idea, it works like a charm and saved me a lot of time! The only difference I intoduced in your code was discard; in fragment shader instead of setting gl_FragColor to zero as you do.

  • Siddharth says:

    Hi Ross,
    I tried your solution but it does not work for me. :(
    I have pasted my whole class :

    public class Lines {

    private final String vertexShaderCode = ” uniform mat4 u_modelViewProjectionMatrix; ” +
    ” uniform mat4 mv; ” +
    ” attribute vec4 a_position; ” +
    ” attribute vec4 a_color; ” +
    ” varying vec4 v_color; ” +
    ” varying vec4 position; ” +

    ” void main() { ” +
    ” gl_Position = u_modelViewProjectionMatrix * a_position; ” +
    ” position = mv * a_position; ” +
    ” v_color = a_color; ” +
    “} ” ;

    private final String fragmentShaderCode = ” precision mediump float; ” +
    ” uniform vec2 sourcePoint; ” +
    ” varying vec4 v_color; ” +
    ” varying vec4 position; ” +

    ” void main() { ” +
    ” if (cos(0.1*abs(distance(sourcePoint.xy, position.xy))) + 0.5 > 0.0) { ” +
    ” gl_FragColor = vec4(0,0,0,0); ” +
    ” } else { ” +
    ” gl_FragColor = v_color; ” +
    ” } ” +
    ” } ” ;

    private final FloatBuffer vertexBuffer;
    private final int mProgram;
    private int mPositionHandle;
    private int mColorHandle;
    private int mMVPMatrixHandle;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 2;
    static float lineCoords[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
    private final int vertexCount = lineCoords.length / COORDS_PER_VERTEX;
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per
    // vertex

    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };

    public Lines() {
    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(
    // (number of coordinate values * 4 bytes per float)
    lineCoords.length * 4);
    // use the device hardware’s native byte order
    bb.order(ByteOrder.nativeOrder());

    // create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    // add the coordinates to the FloatBuffer
    vertexBuffer.put(lineCoords);
    // set the buffer to read the first coordinate
    vertexBuffer.position(0);

    // prepare shaders and OpenGL program
    int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
    vertexShaderCode);
    int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
    fragmentShaderCode);

    mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
    GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader
    // to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment
    // shader to program
    GLES20.glLinkProgram(mProgram); // create OpenGL program executables

    }

    public void draw(float[] mvpMatrix) {

    // Add program to OpenGL environment
    GLES20.glUseProgram(mProgram);

    // get handle to vertex shader’s vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram,”a_position”);

    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
    GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

    // get handle to fragment shader’s vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, “v_color”);

    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

    // get handle to shape’s transformation matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, “uMVPMatrix”);
    MyGLRenderer.checkGlError(“glGetUniformLocation”);

    // Apply the projection and view transformation
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    MyGLRenderer.checkGlError(“glUniformMatrix4fv”);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_LINES, 0, vertexCount);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
    }

    }

    What I need to pass here : mPositionHandle = GLES20.glGetAttribLocation(mProgram,”?????”);

    Please help me.

  • Post a Reply to Siddharth
    Click here to cancel reply.

    Your email is never published nor shared. Required fields are marked *

    *
    *

    return 0;

    }