使用opengles在长时间点击放大

时间:2018-06-06 08:57:42

标签: android opengl-es

我想长时间实施放大。长按此时会出现一个圆圈,其中轻敲区域将显示为缩放。我需要使用opengles。

我使用opengles创建了一个圆圈。它也用手指移动。代码如下:

调用循环onDrawFrame:

public void onDrawFrame(GL10 gl) {
    GLES20.glClearColor(0.53333f, 0.53333f, 0.53333f, 1.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | glES20.GL_DEPTH_BUFFER_BIT);

    if(mMagnifyCircle != null && bLongPressed) {
        mMagnifyCircle.draw();
    }
}

绘制圆圈如下:

public class GLCircle {

private float[] mColor;
private int mProgram;

private float mCenterX;
private float mCenterY;
private float mRadius;

private static final int COORDS_PER_VERTEX = 2;
private static float VERTEX_COORDINATES[] = {
        -1f,   1f,   // top left
        -1f,  -1f,   // bottom left
         1f,  -1f,   // bottom right
         1f,   1f,   // top right
};

private FloatBuffer mVertexBuffer;
private ShortBuffer mDrawListBuffer;

private final short mDrawOrder[] = {0, 1, 2, 0, 2, 3}; // order to draw vertices

public GLCircle(float[] color) {
    mColor = color;

    String vertexShaderSource = "" +
            "attribute vec2 aPosition; \n" +
            "void main() \n" +
            "{ \n" +
            "   gl_Position = vec4(aPosition, 0., 1.); \n" +
            "} \n";

    String fragmentShaderSource = "" +
            "precision highp float;\n" +
            "uniform vec2 aCirclePosition;\n" +
            "uniform float aRadius; \n" +
            "uniform vec4 aColor; \n" +
            "const float threshold = 0.005;\n" +
            "void main() \n" +
            "{ \n" +
            "   float d, dist;\n" +
            "   dist = distance(aCirclePosition, gl_FragCoord.xy);\n" +
            "   if(dist == 0.)\n" +
            "       dist = 1.;\n" +
            "   d = aRadius / dist;\n" +
            "   if(d >= 1.)\n" +
            "        gl_FragColor = aColor;\n" +
            "   else if(d >= 1. - threshold) \n" +
            "   {\n" +
            "        float a = (d - (1. - threshold)) / threshold;\n" +
            "        gl_FragColor = vec4(aColor.r, aColor.g, aColor.b, a); \n" +
            "    }\n" +
            "    else\n" +
            "        gl_FragColor = vec4(0., 0., 0., 0.);\n" +
            "} \n";

    int vertexShader = compileVertexShader(vertexShaderSource);
    int fragmentShader = compileFragmentShader(fragmentShaderSource);
    mProgram = linkProgram(vertexShader, fragmentShader);
    if (BuildConfig.DEBUG) {
        validateProgram(mProgram);
    }

    ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_COORDINATES.length * 4);
    vertexByteBuffer.order(ByteOrder.nativeOrder());
    mVertexBuffer = vertexByteBuffer.asFloatBuffer();
    mVertexBuffer.put(VERTEX_COORDINATES);
    mVertexBuffer.position(0);

    ByteBuffer drawByteBuffer = ByteBuffer.allocateDirect(mDrawOrder.length * 2);
    drawByteBuffer.order(ByteOrder.nativeOrder());
    mDrawListBuffer = drawByteBuffer.asShortBuffer();
    mDrawListBuffer.put(mDrawOrder);
    mDrawListBuffer.position(0);
}

private static int linkProgram(int vertexShaderId, int fragmentShaderId) {
    final int programObjectId = GLES20.glCreateProgram();
    if (programObjectId == 0) {
        return 0;
    }

    GLES20.glAttachShader(programObjectId, vertexShaderId);
    GLES20.glAttachShader(programObjectId, fragmentShaderId);

    GLES20.glLinkProgram(programObjectId);

    final int[] linkStatus = new int[1];
    GLES20.glGetProgramiv(programObjectId, GLES20.GL_LINK_STATUS, linkStatus, 0);

    if (linkStatus[0] == 0) {
        // If it failed, delete the program object. glDeleteProgram(programObjectId);
        GLES20.glDeleteProgram(programObjectId);
        return 0;
    }
    return programObjectId;
}

private static boolean validateProgram(int programObjectId) {
    GLES20.glValidateProgram(programObjectId);
    final int[] validateStatus = new int[1];
    GLES20.glGetProgramiv(programObjectId, GLES20.GL_VALIDATE_STATUS, validateStatus, 0);
    return validateStatus[0] != 0;
}

private static int compileVertexShader(String shaderCode) {
    return compileShader(GLES20.GL_VERTEX_SHADER, shaderCode);
}

private static int compileFragmentShader(String shaderCode) {
    return compileShader(GLES20.GL_FRAGMENT_SHADER, shaderCode);
}

private static int compileShader(int type, String shaderCode) {
    final int shaderObjectId = GLES20.glCreateShader(type);
    if (shaderObjectId == 0) {
        return 0;
    }
    GLES20.glShaderSource(shaderObjectId, shaderCode);
    GLES20.glCompileShader(shaderObjectId);

    final int[] compileStatus = new int[1];
    GLES20.glGetShaderiv(shaderObjectId, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

    if (compileStatus[0] == 0) {
        GLES20.glDeleteShader(shaderObjectId);
        return 0;
    }
    return shaderObjectId;
}

public void draw() {
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    GLES20.glUseProgram(mProgram);

    int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    int vertexStride = COORDS_PER_VERTEX * 4;
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, mVertexBuffer);

    GLES20.glUniform4fv(GLES20.glGetUniformLocation(mProgram, "aColor"), 1, mColor, 0);
    GLES20.glUniform2f(GLES20.glGetUniformLocation(mProgram, "aCirclePosition"), mCenterX, mCenterY);
    GLES20.glUniform1f(GLES20.glGetUniformLocation(mProgram, "aRadius"), mRadius);
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, mDrawOrder.length, GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer);
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}

public float getCenterX() {
    return mCenterX;
}

public void setCenterX(float centerX) {
    mCenterX = centerX;
}

public float getCenterY() {
    return mCenterY;
}

public void setCenterY(float centerY) {
    mCenterY = centerY;
}

public float getRadius() {
    return mRadius;
}

public void setRadius(float radius) {
    this.mRadius = radius;
}

}

继续手指触摸:

    @Override
public boolean onTouch(View v, MotionEvent event) {
    boolean bResult = false;
    float x = 0,y = 0;

    if (event.getAction() == MotionEvent.ACTION_DOWN){
        x = event.getRawX();
        y = event.getRawY();
    } else if (event.getAction() == MotionEvent.ACTION_UP) {
        bLongPressed = false;
        requestRenderer();
        GLES20.glClearColor(0.53333f, 0.53333f, 0.53333f, 1.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        v.performClick();
    } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
        x = event.getRawX();
        y = event.getRawY();
    }

    requestRenderer();
    mMagnifyCircle.setCenterX(x);
    mMagnifyCircle.setCenterY(y);
    mMagnifyCircle.setRadius(200);
    return bResult;
}

我的问题是:

  1. 如果我在x轴上移动手指,则用手指圈出。但是,如果我搬家 手指在Y轴上,圆圈向相反方向移动。怎么解决 这个?
  2. 圆圈已经透明了。但我想只放大圆圈 区域。我怎么能这样做?
  3. 预期输出如下所示:

    Expected feature will be look like below:

1 个答案:

答案 0 :(得分:1)

在视图空间中,y坐标从底部指向顶部。

view space

这意味着gl_FragCoord的y分量是视口底部的0和视口顶部窗口的高度。

但对于由aCirclePosition mCenterX设置的mCenterY,窗口顶部为0,底部为窗口的高度。

要解决此问题,您必须知道窗口高度的高度(window_height在以下代码段中),您必须翻转y坐标。设置制服aCirclePosition

时可以完成这个问题
int pos_loc = GLES20.glGetUniformLocation(mProgram, "aCirclePosition");
GLES20.glUniform2f(pos_loc, mCenterX, window_height-mCenterY);