24

If I have custom renderer in opengl-es prepared:

public void onDrawFrame(GL10 gl)
{
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    // here i want to draw line from [0, 0, 0] to [1, 0, 0]
}

What is the easiest and shortest way to draw line?

In ordinary OpenGL it is:

glBegin(GL_LINES);
    glVertex3f(0, 0, 0);
    glVertex3f(1, 0, 0);
glEnd();

But how can i get the same effect with OpenGL ES?

Michal
  • 3,584
  • 9
  • 47
  • 74
  • Check e.g. http://stackoverflow.com/questions/11015374/opengl-es-2-0-drawing-line-based-on-motion-line-always-starts-in-origin You don't have to have the matrix stuff, or even a program/shader in order to draw black lines. But there's a need to get the buffers correct in order to use gl.drawElements(GL.LINES, xxx); – Aki Suihkonen Apr 16 '13 at 04:20

2 Answers2

41

I am new to new to OpenGL ES 2.0 but I created a line class.

public class Line {
    private FloatBuffer VertexBuffer;

    private final String VertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +

        "attribute vec4 vPosition;" +
        "void main() {" +
        // the matrix must be included as a modifier of gl_Position
        "  gl_Position = uMVPMatrix * vPosition;" +
        "}";

    private final String FragmentShaderCode =
        "precision mediump float;" +
        "uniform vec4 vColor;" +
        "void main() {" +
        "  gl_FragColor = vColor;" +
        "}";
    
    protected int GlProgram;
    protected int PositionHandle;
    protected int ColorHandle;
    protected int MVPMatrixHandle;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
    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

    // Set color with red, green, blue and alpha (opacity) values
    float color[] = { 0.0f, 0.0f, 0.0f, 1.0f };

    public Line() {
        // 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);
    
        int vertexShader = ArRenderer.loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode);
        int fragmentShader = ArRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode);

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

    public void SetVerts(float v0, float v1, float v2, float v3, float v4, float v5) {
        LineCoords[0] = v0;
        LineCoords[1] = v1;
        LineCoords[2] = v2;
        LineCoords[3] = v3;
        LineCoords[4] = v4;
        LineCoords[5] = v5;
    
        VertexBuffer.put(LineCoords);
        // set the buffer to read the first coordinate
        VertexBuffer.position(0);
    }

    public void SetColor(float red, float green, float blue, float alpha) {
        color[0] = red;
        color[1] = green;
        color[2] = blue;
        color[3] = alpha;
    }

    public void draw(float[] mvpMatrix) {
        // Add program to OpenGL ES environment
        GLES20.glUseProgram(GlProgram);

        // get handle to vertex shader's vPosition member
        PositionHandle = GLES20.glGetAttribLocation(GlProgram, "vPosition");

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

        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(PositionHandle, COORDS_PER_VERTEX,
                                 GLES20.GL_FLOAT, false,
                                 VertexStride, VertexBuffer);

        // get handle to fragment shader's vColor member
        ColorHandle = GLES20.glGetUniformLocation(GlProgram, "vColor");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(ColorHandle, 1, color, 0);
    
        // get handle to shape's transformation matrix
        MVPMatrixHandle = GLES20.glGetUniformLocation(GlProgram, "uMVPMatrix");
        ArRenderer.checkGlError("glGetUniformLocation");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
        ArRenderer.checkGlError("glUniformMatrix4fv");

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

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

And then in my Render class I create my line objects and to a container so the get draw in the by iterating over the items and calling the Line.draw method in onDrawFrame.

Here are some lines I create to make a horizon:

    Line eastHorz = new Line();
    eastHorz.SetVerts(10f, 10f, 0f, 10f, -10f, 0f);
    eastHorz.SetColor(.8f, .8f, 0f, 1.0f);
    Line northHorz = new Line();
    northHorz.SetVerts(-10f, 10f, 0f, 10f, 10f, 0f);
    northHorz.SetColor(0.8f, 0.8f, 0f, 1.0f);
    Line westHorz = new Line();
    westHorz.SetVerts(-10f, -10f, 0f, -10f, 10f, 0f);
    westHorz.SetColor(0.8f, 0.8f, 0f, 1.0f);
    Line southHorz = new Line();
    southHorz.SetVerts(-10f, -10f, 0f, 10f, -10f, 0f);
    southHorz.SetColor(0.8f, 0.8f, 0f, 1.0f);
    Lines.add(eastHorz);
    Lines.add(northHorz);
    Lines.add(westHorz);
    Lines.add(southHorz);

ArRenderer is my render class which holds the Lines, camera position etc and implements GLSurfaceView.Renderer. The loadShader method is:

public static int loadShader(int type, String shaderCode) { 
    // create a vertex shader type (GLES20.GL_VERTEX_SHADER) 
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) 
    int shader = GLES20.glCreateShader(type); 
    
    // add the source code to the shader and compile it 
    GLES20.glShaderSource(shader, shaderCode); 
    GLES20.glCompileShader(shader); 
    return shader; 
}
cod3monk3y
  • 9,508
  • 6
  • 39
  • 54
Rodney Lambert
  • 707
  • 6
  • 7
  • 24
    I can't get over how much more effort it is to draw a line in OpenGLES2 than OpenGL. 6 lines becomes several dozen :( – zyzof Sep 25 '13 at 07:24
  • 1
    what is ArRenderer please – Sun Nov 04 '14 at 02:27
  • 1
    Ravi - ArRenderer is my render class that I mention above it holds the Lines, camera position etc and implements GLSurfaceView.Renderer. The loadShader method is: public static int loadShader(int type, String shaderCode){ // create a vertex shader type (GLES20.GL_VERTEX_SHADER) // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(type); // add the source code to the shader and compile it GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } – Rodney Lambert Nov 05 '14 at 11:22
  • What parameters are you sending to Matrix.setLookAtM() ? My code runs without errors, but I don't see anything being drawn. – sideways8 Feb 17 '15 at 23:31
  • ArRenderer.checkGlError() ? You should localize those function calls, for one thing, it's horrible coupling not to. – Tatarize Feb 25 '15 at 09:28
  • I have put your code in a single file but it's not working: http://pastebin.com/nncq0h2m The screen is scrambled. Any idea what's wrong? – gregoiregentil Feb 11 '16 at 21:28
  • Forget. It's working now... I just had to add a glclear – gregoiregentil Feb 11 '16 at 21:44
  • You probably want to use GL_LINE_STRIP instead of GL_LINES. GL_LINES won't work correctly if you have more than 2 points. – Tim Autin Jul 17 '18 at 15:55
  • What is ArRenderer over here? I am not getting idea, have also gone through your previous comments. Can you please help me with that ? @RodneyLambert – Yesha Shah Feb 04 '21 at 10:11
8

Thanks Rodney Lambert for the Line class you´ve provided. However it also would be nice to provide a simpler call in onDrawFrame, something like:

Line vertLine = new Line();
vertLine.SetVerts(-0.5f, 0.5f, 0f, -0.5f, -0.5f, 0f);
vertLine.SetColor(.8f, .8f, 0f, 1.0f);
vertLine.draw(mMVPMatrix);

vertLine.SetVerts(-0.5f, 0.5f, 0f, -0.5f, -0.5f, 0f);

creates definitely a line visible inside the viewport

escalator
  • 888
  • 9
  • 14