opengl shader实现透视变换效果

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010302327/article/details/82116484

想在手机上实现透视变换的效果,可是不想加opencv,所以只能找opengl的方法,经过不停的寻找终于让我找到了外国一个大神写的算法,写入代码,一运行

效果非常好,除了有锯齿,然后发现网页不知道什么时候被我关闭了,找了半天找不到了,算了如果有人发现请告诉我,谢谢

接下来贴代码

public class TestActivity extends Activity implements GLSurfaceView.Renderer {

    private GLSurfaceView view;

    int[] status = new int[1];

    int program;

    FloatBuffer attributeBuffer;

    FloatBuffer positionBuffer;

    ShortBuffer indicesBuffer;

    short[] indicesData;

    float[] attributesData;

    float[] positionData;

    private int[] textureIds = new int[1];

    int textureId;

    int attributePosition;

    int attributeRegion;



    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);



        view = new GLSurfaceView(this);

        view.setEGLContextClientVersion(2);

        view.setRenderer(this);



        setContentView(view);

    }



    @Override

    public void onPause() {

        view.onPause();



        super.onPause();

    }



    @Override

    public void onResume() {

        super.onResume();



        view.onResume();

    }



    public void onDrawFrame(GL10 gl) {

        GLES20.glClearColor(0f, 0f, 0f, 1f);

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);



        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);



        drawNonAffine(100, 0, 600, 150, 700, 400, 50, 500);




        positionBuffer.position(0);
        positionBuffer.put(positionData);
        positionBuffer.position(0);

        GLES20.glVertexAttribPointer(attributePosition, 2, GLES20.GL_FLOAT, false, 2 * 4, positionBuffer);

        GLES20.glEnableVertexAttribArray(attributePosition);




        attributeBuffer.position(0);
        attributeBuffer.put(attributesData);
        attributeBuffer.position(0);

        GLES20.glVertexAttribPointer(attributeRegion, 3, GLES20.GL_FLOAT, false, 3 * 4, attributeBuffer);

        GLES20.glEnableVertexAttribArray(attributeRegion);



        indicesBuffer.position(0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);

    }



    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        String vertexShaderSource =

                "attribute vec2 a_Position;" +

                        "attribute vec3 a_Region;" +

                        "varying vec3 v_Region;" +

                        "uniform mat3 u_World;" +

                        "void main()" +

                        "{" +

                        "   v_Region = a_Region;" +

                        "   vec3 xyz = u_World * vec3(a_Position, 1);" +

                        "   gl_Position = vec4(xyz.xy, 0, 1);" +

                        "}";



        String fragmentShaderSource =

                "precision mediump float;" +

                        "varying vec3 v_Region;\n" +

                        "uniform sampler2D u_TextureId;\n" +


                        "void main(){\n" +
                        "   vec2 r = v_Region.xy / v_Region.z;\n"+
                        "   vec4 out_color = texture2D(u_TextureId, r);\n"+
                        "   gl_FragColor = out_color;"+
                        "}";


        attributeBuffer = ByteBuffer.allocateDirect(3 * 4 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();

        positionBuffer = ByteBuffer.allocateDirect(2 * 4 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();

        attributesData = new float[3 * 4];

        positionData = new float[2*4];


        indicesBuffer = ByteBuffer.allocateDirect(6 * 2).order(ByteOrder.nativeOrder()).asShortBuffer();

        indicesData = new short[] { 0, 1, 2, 2, 3, 0 };



        indicesBuffer.position(0);

        indicesBuffer.put(indicesData);



        program = loadProgram(vertexShaderSource, fragmentShaderSource);

        textureId = loadTexture();



        GLES20.glUseProgram(program);



        float width = view.getWidth();

        float height = view.getHeight();

        float world[] = new float[] {

                2f / width, 0, 0,

                0, 2f / height, 0,

                -1f, -1f, 1

        };



        int uniformWorld = GLES20.glGetUniformLocation(program, "u_World");

        int uniformTextureId = GLES20.glGetUniformLocation(program, "u_TextureId");



        GLES20.glUniformMatrix3fv(uniformWorld, 1, false, world, 0);

        GLES20.glUniform1i(uniformTextureId, 0);



        attributePosition = GLES20.glGetAttribLocation(program, "a_Position");

        attributeRegion = GLES20.glGetAttribLocation(program, "a_Region");

    }



    public void setFilters(int minFilter, int magFilter) {

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, minFilter);

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, magFilter);

    }



    public void setWrapping(int wrapS, int wrapT) {

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, wrapS);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, wrapT);

    }



    public void drawNonAffine(float bottomLeftX, float bottomLeftY, float bottomRightX, float bottomRightY, float topRightX, float topRightY, float topLeftX, float topLeftY) {

        float ax = topRightX - bottomLeftX;

        float ay = topRightY - bottomLeftY;

        float bx = topLeftX - bottomRightX;

        float by = topLeftY - bottomRightY;



        float cross = ax * by - ay * bx;



        boolean rendered = false;



        if (cross != 0) {

            float cy = bottomLeftY - bottomRightY;

            float cx = bottomLeftX - bottomRightX;



            float s = (ax * cy - ay * cx) / cross;



            if (s > 0 && s < 1) {

                float t = (bx * cy - by * cx) / cross;



                if (t > 0 && t < 1) {

                    //uv coordinates for texture



                    float lbx = 0;          // left bottom x
                    float lby = 1;          // left bottom y

                    float rbx = 1;          //right bottom x
                    float rby = 1;          //right bottom y

                    float rtx = 1;          //right top x
                    float rty = 0;          //right top y

                    float ltx = 0;          //left top x
                    float lty = 0;          //left top x




//                    float u0 = 0; // texture bottom left u   x
//
//                    float v0 = 0; // texture bottom left v   y
//
//                    float u2 = 1; // texture top right u     x
//
//                    float v2 = 1; // texture top right v     y



                    int bufferIndex = 0;



                    float q0 = 1 / (1 - t);

                    float q1 = 1 / (1 - s);

                    float q2 = 1 / t;

                    float q3 = 1 / s;



                    positionData[bufferIndex++] = bottomLeftX;

                    positionData[bufferIndex++] = bottomLeftY;

                    positionData[bufferIndex++] = bottomRightX;

                    positionData[bufferIndex++] = bottomRightY;

                    positionData[bufferIndex++] = topRightX;

                    positionData[bufferIndex++] = topRightY;

                    positionData[bufferIndex++] = topLeftX;

                    positionData[bufferIndex++] = topLeftY;


                    bufferIndex = 0;

                    attributesData[bufferIndex++] = lbx * q0;

                    attributesData[bufferIndex++] = lby * q0;

                    attributesData[bufferIndex++] = q0;

                    attributesData[bufferIndex++] = rbx * q1;

                    attributesData[bufferIndex++] = rby * q1;

                    attributesData[bufferIndex++] = q1;

                    attributesData[bufferIndex++] = rtx * q2;

                    attributesData[bufferIndex++] = rty * q2;

                    attributesData[bufferIndex++] = q2;

                    attributesData[bufferIndex++] = ltx * q3;

                    attributesData[bufferIndex++] = lty * q3;

                    attributesData[bufferIndex++] = q3;



                    rendered = true;

                }

            }

        }



        if (!rendered) {

            throw new RuntimeException("Shape must be concave and vertices must be clockwise.");

        }

    }



    public void onSurfaceChanged(GL10 gl, int width, int height) {

        GLES20.glViewport(0, 0, width, height);

    }



    private int loadTexture() {


        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.forest);



        GLES20.glGenTextures(1, textureIds, 0);



        int textureId = textureIds[0];



        if (textureId == 0) {

            throw new RuntimeException("Could not generate texture.");

        }



        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);



        setFilters(GLES20.GL_LINEAR, GLES20.GL_LINEAR);

        setWrapping(GLES20.GL_CLAMP_TO_EDGE, GLES20.GL_CLAMP_TO_EDGE);



        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);



        bitmap.recycle();



        return textureId;

    }



    private int loadProgram(String vertexShaderSource, String fragmentShaderSource) {

        int id = GLES20.glCreateProgram();



        int vertexShaderId = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderSource);

        int fragmentShaderId = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderSource);



        GLES20.glAttachShader(id, vertexShaderId);

        GLES20.glAttachShader(id, fragmentShaderId);

        GLES20.glLinkProgram(id);

        GLES20.glDeleteShader(vertexShaderId);

        GLES20.glDeleteShader(fragmentShaderId);

        GLES20.glGetProgramiv(id, GLES20.GL_LINK_STATUS, status, 0);



        if (status[0] == 0) {

            String log = GLES20.glGetProgramInfoLog(id);



            GLES20.glDeleteProgram(id);



            throw new RuntimeException("Shader error:" + log);

        }



        return id;

    }



    private int loadShader(int type, String source) {

        int id = GLES20.glCreateShader(type);



        GLES20.glShaderSource(id, source);

        GLES20.glCompileShader(id);

        GLES20.glGetShaderiv(id, GLES20.GL_COMPILE_STATUS, status, 0);



        if (status[0] == 0) {

            String log = GLES20.glGetShaderInfoLog(id);



            GLES20.glDeleteShader(id);



            throw new RuntimeException("Shader error:" + log);

        }



        return id;

    }



    private void checkGlError(String op) {

        int error;



        if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {

            throw new RuntimeException("GL error code: " + error + " for " + op + ".");

        }

    }

}

接下来贴图像校正效果

校正到

还有点畸形,这是我简单的调试了一下,坐标都是我加一点加一点推出来的,想很好必须找出4个点的精准坐标进行换算

贴代码

  public void drawNonAffine(float bottomLeftX, float bottomLeftY, float bottomRightX, float bottomRightY, float topRightX, float topRightY, float topLeftX, float topLeftY) {

        float ax = topRightX - bottomLeftX;

        float ay = topRightY - bottomLeftY;

        float bx = topLeftX - bottomRightX;

        float by = topLeftY - bottomRightY;



        float cross = ax * by - ay * bx;



        boolean rendered = false;



        if (cross != 0) {

            float cy = bottomLeftY - bottomRightY;

            float cx = bottomLeftX - bottomRightX;



            float s = (ax * cy - ay * cx) / cross;



            if (s > 0 && s < 1) {

                float t = (bx * cy - by * cx) / cross;



                if (t > 0 && t < 1) {

                    //uv coordinates for texture

                    float lbx = 0;          // left bottom x
                    float lby = 1;          // left bottom y

                    float rbx = 0.83f;      //right bottom x
                    float rby = 1;          //right bottom y

                    float rtx = 1;          //right top x
                    float rty = 0;          //right top y

                    float ltx = 0.17f;      //left top x
                    float lty = 0.275f;     //left top x


//                    float u0 = 0; // texture bottom left u   x
//
//                    float v0 = 0; // texture bottom left v   y
//
//                    float u2 = 1; // texture top right u     x
//
//                    float v2 = 1; // texture top right v     y



                    int bufferIndex = 0;



                    float q0 = 1 / (1 - t);

                    float q1 = 1 / (1 - s);

                    float q2 = 1 / t;

                    float q3 = 1 / s;



                    positionData[bufferIndex++] = bottomLeftX;

                    positionData[bufferIndex++] = bottomLeftY;

                    positionData[bufferIndex++] = bottomRightX;

                    positionData[bufferIndex++] = bottomRightY;

                    positionData[bufferIndex++] = topRightX;

                    positionData[bufferIndex++] = topRightY;

                    positionData[bufferIndex++] = topLeftX;

                    positionData[bufferIndex++] = topLeftY;


                    bufferIndex = 0;

                    attributesData[bufferIndex++] = lbx * q0;

                    attributesData[bufferIndex++] = lby * q0;

                    attributesData[bufferIndex++] = q0;

                    attributesData[bufferIndex++] = rbx * q1;

                    attributesData[bufferIndex++] = rby * q1;

                    attributesData[bufferIndex++] = q1;

                    attributesData[bufferIndex++] = rtx * q2;

                    attributesData[bufferIndex++] = rty * q2;

                    attributesData[bufferIndex++] = q2;

                    attributesData[bufferIndex++] = ltx * q3;

                    attributesData[bufferIndex++] = lty * q3;

                    attributesData[bufferIndex++] = q3;



                    rendered = true;

                }

            }

        }



        if (!rendered) {

            throw new RuntimeException("Shape must be concave and vertices must be clockwise.");

        }

    }

我改的就是纹理坐标的8个点的数据,lbx,lby,rbx,rby,rtx,rty,ltx,lty

drawNonAffine(0, 0, 194, 0, 194, 257, 0, 257);

我传入的是图片的长宽,也可以自己设置一个矩形,只要不是不规则四边形就可以了

猜你喜欢

转载自blog.csdn.net/u010302327/article/details/82116484