在纹理Open GL ES 2.0 Android上画一条线

时间:2016-06-08 13:59:18

标签: android opengl-es

我在这里有一个简单的问题。我使用纹理来渲染位图,一切都很好。但是我想在所述纹理上绘制一条线。我知道vert / tex坐标是如何工作的,但由于某些未知原因我无法实现这一点。在调用之后,我正在调用绘制我的线条,将位图绘制到纹理,但只有位图显示为静止。实现这一目标的最佳方法是什么?我正在使用texure2D在我的片段着色器中绘制位图,是否需要添加一些东西来绘制具有指定颜色的线条?任何帮助将不胜感激。

感谢。

与位图纹理相关的代码:

 private final String vertexTextureShaderCode =
                "attribute vec4 aPosition;"+ // Position of out Vertex
                "attribute vec2 aTexPosition;"+ // Position of our texture contained in the vertex
                "varying vec2 vTexPosition;"+ //
                "void main(){"+
                "    gl_Position = aPosition;"+
                "    vTexPosition = aTexPosition;"+
                "}";


private final String fragmentTextureShaderCode =
                "precision mediump float;" +
                "uniform sampler2D uTexture;" + // Our Background Image  ( Our uploaded image)
                "varying vec2 vTexPosition;" +
                "void main() {" +
                "  gl_FragColor = texture2D(uTexture, vTexPosition);" +
                "}";

public void draw(float[] m ,ImageEffectFactory effectFactory,int currentEffect){
    // add program to OpenGl ES Environment;
    this.imageEffectFactory = effectFactory;
    boolean effectChanged = false;
    if(currentEffect != mCurrentEffect){
        mCurrentEffect = currentEffect;
        effectChanged = true;
    }

    int whichTexture = 0;
    if(currentEffect > 0 && currentEffect < 6){
        whichTexture = 1;
        if(effectChanged) {
            imageEffectFactory.applyEffect(mTexturePointer, ImageEffectFactory.FILTER.values()[currentEffect], mTextureImageWidth, mTextureImageHeight);
            effectChanged = false;
        }
    }

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    GLES20.glUseProgram(mProgram);
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

    GLES20.glViewport(0,0,mViewWidth, mViewHeight);

    // get handle to vertex shader vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
    mTextureHandle = GLES20.glGetUniformLocation(mProgram, "uTexture");
    mTexturePositionHandle = GLES20.glGetAttribLocation(mProgram, "aTexPosition");


    GLES20.glVertexAttribPointer(mTexturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, mTextureBuffer);
    GLES20.glEnableVertexAttribArray(mTexturePositionHandle);

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturePointer[whichTexture]);
    GLES20.glUniform1i(mTextureHandle,0);

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

    // enable a handle to the triangle vertice
    GLES20.glEnableVertexAttribArray(mPositionHandle);


    // Draw the square
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);

    // Disbale the vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);


}

正如我所提到的,这很好用。我试图加载的位图将显示并看起来很完美。但是在绘制之后我试图绘制线条。以下是该行的设置:

private static final String vsShader =
        "uniform mat4 uMVPMatrix;"+
        "attribute vec4 vPosition; " +
        "void main() { " +
        "   gl_Position = uMVPMatrix * vPosition;" +
        " }";

private static final String fsShader =
        "precision mediump float;"
        + "uniform vec4 vColor;"
        + "void main() {"
        + "gl_FragColor = vColor;" +
        "}";

 private float[] pathCoords = {
        -0.5f, 0.5f,0.0f,
        -0.5f, -0.5f, 0.0f
};


private short[] pathDrawOrder = {0,1};
    private float[] color = {1.0f, 0.0f, 0.0f, 1.0f}; //  - red for testing
    private final FloatBuffer mVertBuffer;
private final ShortBuffer mDrawListBuffer;


private int mCropProgram;

private int vPositionHandle;
private int vColorHandle;
private int uMVPMatrixHandle;

public CropFrameRect(Context context){
    this.context = context;

    // Allocat a byteBuffer for our Vertex Array;
    ByteBuffer bb = ByteBuffer.allocateDirect(pathCoords.length * 4);

    // ORder those Bytes correctly depending on the device (ie. BIG-ENDIAN vs. LITTLE-ENDIAN
    bb.order(ByteOrder.nativeOrder());

    // Lets now store those vertex points into a FloatBuffer please.
    mVertBuffer = bb.asFloatBuffer();
    mVertBuffer.put(pathCoords);
    mVertBuffer.position(0);

    ByteBuffer dlb = ByteBuffer.allocateDirect(pathDrawOrder.length*2);
    dlb.order(ByteOrder.nativeOrder());

    mDrawListBuffer = dlb.asShortBuffer();
    mDrawListBuffer.put(pathDrawOrder);
    mDrawListBuffer.position(0);

    int vertexShader = ImageGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vsShader);

    int fragmentShader = ImageGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fsShader);

    // We've compiled our vertex and our texture shader programs. Let us create the program..
    mCropProgram = GLES20.glCreateProgram();

    // Attach the vertex shader string
    GLES20.glAttachShader(mCropProgram, vertexShader);

    // Attach the shader program string
    GLES20.glAttachShader(mCropProgram, fragmentShader);

    // Link the program code to the OpenGL Context
    GLES20.glLinkProgram(mCropProgram);

    Log.d(TAG, "Crop Program Linked: " + mCropProgram);
}

public void draw(float[] matrix){
    GLES20.glUseProgram(mCropProgram);



    vPositionHandle = GLES20.glGetAttribLocation(mCropProgram, "vPosition");
    GLES20.glEnableVertexAttribArray(vPositionHandle);
    GLES20.glVertexAttribPointer(vPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, mVertBuffer);

    // set the color
    vColorHandle = GLES20.glGetUniformLocation(mCropProgram, "vColor");
    GLES20.glUniform4fv(vColorHandle, 1, color, 0);

    // set the Matrix projection for the View;
    uMVPMatrixHandle = GLES20.glGetUniformLocation(mCropProgram, "uMVPMatrix");
    GLES20.glUniformMatrix4fv(uMVPMatrixHandle, 1, false, matrix, 0);

    GLES20.glLineWidth(2.7f);


    // Draw those elements
    GLES20.glDrawElements(GLES20.GL_LINES, pathDrawOrder.length, GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer);

    GLES20.glDisableVertexAttribArray(vPositionHandle);
    GLES20.glDisable(vColorHandle);

}

2 个答案:

答案 0 :(得分:0)

首先,一些关于你正在做的事情的代码可能证明是有用的。如果纹理显示正确,我只能猜测绘制线条有问题。但是图纸失败的原因很多。

第二个问题标题是“如何在纹理上绘制线条”,而描述似乎是在询问如何在绘制的纹理上绘制线条。注意这两个是非常不同的,因为绘制纹理是很常见的。

因此,如果您已成功将纹理绘制到视图中但未能在其上绘制线条,那么我想最好开始调试该问题。您应该首先尝试绘制没有纹理的线条,看看它是否绘制。 如果没有:

  • 检查坐标是否有意义
  • 检查矩阵是否有意义,甚至禁用它们(使用标识)进行调试
  • 检查着色器是否绘制线条,因为您很可能需要单独的着色器来绘制纯色而不是纹理
  • 检查是否设置了线宽
  • 如果全部失败,则创建一个新的着色器,输出硬编码的纯色(例如白色),除了位置之外什么也不做,创建顶点(0,0), (1,1)并将它们绘制成一条线。除了清除缓冲区之外,不应该绘制任何其他内容并且不应该调用openGL。在此工作之后,您可以从此开始向上构建并查看您的错误所在。

如果它直接从删除调用中绘制以绘制纹理,那么我最好的猜测是你启用了深度测试,并且该行位于纹理后面。尝试禁用深度测试或尝试将线条靠近一点。

答案 1 :(得分:0)

您必须为此代码更改fragmentTextureShaderCode。

private final String fragmentTextureShaderCode =
                "precision mediump float;" +
                "vec2 u_line_prop" + //line slope and bias 
                "uniform vec2 u_resolution;" + //width, height GlSurfaceTexture
                "uniform sampler2D uTexture;" + // Our Background Image  ( Our uploaded image)
                "varying vec2 vTexPosition;" +
// Plot a line on Y using a value between 0.0-1.0
                "float plotLine(vec2 st, float pct){" +
                "  return  smoothstep( pct-0.02, pct, st.y) -" +
                "  smoothstep( pct, pct+0.02, st.y);" +
                "}" +


                "void main() {" +
                "  vec2 st = gl_FragCoord.xy/u_resolution.xy;" +
                "  st.x *= u_resolution.x/u_resolution.y;" +
                //line formula
                "  float y = st.x*u_line_prop.x+u_line_prop.y;" +
                "  float pct = plotLine(st,y);" +    
                "  colorLine = texture2D(uTexture, vTexPosition);" +
                "  vec4 colorLine = vec4 (1.0,1.0, 0.0,1.0) ;" +
                "  gl_FragColor = mix(colorTexture, colorLine, pct);"  
                "}";

然后你必须更正你的java代码以传输另外两个向量:

  • u_line_prop //线斜率和偏差
  • u_resolution // width,height GlSurfaceTexture 不需要该行的着色器程序!

您可以在线Shaders editor查看类似代码的工作原理