【问题标题】:How to render large size image with OpenGL ES 2.0 on android如何在 android 上使用 OpenGL ES 2.0 渲染大尺寸图像
【发布时间】:2017-01-09 16:14:05
【问题描述】:

我正在尝试通过 OpenGL ES 2.0 在 android OS 上更改图像的颜色。这是我的代码。

文本类

public class Tex {
    private FloatBuffer mVertexBuffer;
    private ShortBuffer mDrawListBuffter;
    protected FloatBuffer mUvBuffer;
    protected static float mUvs[];
    private final float[] mMtrxView = new float[16];
    public static final String vs_Image
            = "uniform mat4 uMVPMatrix;"
            + "attribute vec4 vPosition;"
            + "attribute vec2 a_texCoord;"
            + "varying vec2 v_texCoord;"
            + "void main() {"
            + "     gl_Position = uMVPMatrix * vPosition;"
            + "     v_texCoord = a_texCoord;"
            + "}";
    public static final String fs_Image
            = "precision mediump float;"
            + "varying vec2 v_texCoord;"
            + "uniform sampler2D s_texture;"
            + "void main() {"
            + "     vec4 tex = texture2D(s_texture, v_texCoord);"
            + "     float tintR = 0.6;"
            + "     float tintG = 0.3;"
            + "     float tintB = 0.0;"
            + "     float tr = clamp(tex.r * (1.0 - tintR) + tintR, 0.0, 1.0);"
            + "     float tg = clamp(tex.g * (1.0 - tintG) + tintG, 0.0, 1.0);"
            + "     float tb = clamp(tex.b * (1.0 - tintB) + tintB, 0.0, 1.0);"
            + "     gl_FragColor = vec4(tr, tg, tb, tex.a);"
            + "}";
    float mSquareCoords[] = {
            -1.0f, 1.0f, 0.0f,
            -1.0f, -1.0f, 0.0f,
            1.0f, -1.0f, 0.0f,
            1.0f, 1.0f, 0.0f
    };
    private short mDrawOrder[] = {0, 1, 2, 0, 2, 3};
    private final int mProgram;
    int[] mTextureNames;
    MainGLRenderer mMainGLRenderer;
    int mWidth, mHeight;
    Bitmap mBitmap;

    public Tex(MainGLRenderer mainGLRenderer, Bitmap bitmap) {
        mMainGLRenderer = mainGLRenderer;

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

        ByteBuffer dlb = ByteBuffer.allocateDirect(mDrawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        mDrawListBuffter = dlb.asShortBuffer();
        mDrawListBuffter.put(mDrawOrder);
        mDrawListBuffter.position(0);

        mUvs = new float[] {
                0.0f, 0.0f,
                0.0f, 1.0f,
                1.0f, 1.0f,
                1.0f, 0.0f,
        };
        ByteBuffer bbUvs = ByteBuffer.allocateDirect(mUvs.length * 4);
        bbUvs.order(ByteOrder.nativeOrder());
        mUvBuffer = bbUvs.asFloatBuffer();
        mUvBuffer.put(mUvs);
        mUvBuffer.position(0);

        int vertexShader = mMainGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vs_Image);
        int fragmentShader = mMainGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fs_Image);

        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);
        GLES20.glLinkProgram(mProgram);

        initTexture(bitmap);
    }

    private void initTexture(Bitmap bitmap) {
        mWidth = bitmap.getWidth();
        mHeight = bitmap.getHeight();
        GLES20.glViewport(0, 0, mWidth, mHeight);

        mTextureNames = new int[1];
        GLES20.glGenTextures(1, mTextureNames, 0);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureNames[0]);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        draw();
    }

    public void draw() {
        GLES20.glUseProgram(mProgram);
        Matrix.setIdentityM(mMtrxView, 0);

        int positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(positionHandle);
        GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexBuffer);

        int texCoordLoc = GLES20.glGetAttribLocation(mProgram, "a_texCoord");
        GLES20.glEnableVertexAttribArray(texCoordLoc);
        GLES20.glVertexAttribPointer(texCoordLoc, 2, GLES20.GL_FLOAT, false, 0, mUvBuffer);

        int mtrxHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        GLES20.glUniformMatrix4fv(mtrxHandle, 1, false, mMtrxView, 0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureNames[0]);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, mDrawOrder.length, GLES20.GL_UNSIGNED_SHORT, mDrawListBuffter);

        GLES20.glDisableVertexAttribArray(positionHandle);
        GLES20.glDisableVertexAttribArray(texCoordLoc);

        mBitmap = getBitmap();
    }

    public Bitmap getBitmap() {    
        IntBuffer intBuffer = IntBuffer.allocate(mWidth * mHeight);
        GLES20.glReadPixels(0, 0, mWidth, mHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, intBuffer);

        int[] intArrayO = intBuffer.array();
        int[] intArrayR = new int[mWidth * mHeight];
        for (int i = 0; i < mHeight; i++) {
            for (int j = 0; j < mWidth; j++) {
                intArrayR[(mHeight - i - 1) * mWidth + j] = intArrayO[i * mWidth + j];
            }
        }

        Bitmap postBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
        postBitmap.copyPixelsFromBuffer(intBuffer.wrap(intArrayR));

        return postBitmap;
    }

    public Bitmap getmBitmap() {
        return mBitmap;
    }
}

MainActivity 中的 onClick 方法

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_run:
                Bitmap bitmap = mGLSurfaceView.mRenderer.mTex.getmBitmap();
                mImageView.setImageBitmap(bitmap);

                String storageDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + Environment.DIRECTORY_DCIM + "/Camera";
                File dir = new File(storageDir);
                if (!dir.exists()) dir.mkdir();

                String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
                String path = storageDir + "/IMG_" + timeStamp + ".jpg";
                File file = new File(path);

                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                byte[] byteData = stream.toByteArray();

                try {
                    FileOutputStream fos = new FileOutputStream(file);
                    fos.write(byteData);
                    fos.flush();
                    fos.close();
                }
                catch (Exception e) {

                }

                Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                Uri uri = Uri.parse("file://" + path);
                intent.setData(uri);
                sendBroadcast(intent);
                break;
        }
    }

如上代码所示,onClick() 方法调用getmBitmap() 方法,然后我可以得到渲染图像。它适用于小分辨率图像。但是,对于 3840 x 2160 这样的高分辨率,渲染图像是异常的。在渲染图像中,小比例和颜色变化的原始图像位于左下角。其余区域用黑色填充。我不知道出了什么问题。我必须为高分辨率图像设置一些东西吗?我需要建议。请帮忙。

【问题讨论】:

    标签: android image opengl-es


    【解决方案1】:

    你要渲染什么?

    您正在上传更大的纹理,但如果您不更改正在渲染的帧缓冲区的大小,那么您将无法获得更大的图像。

    【讨论】:

    • 如何改变帧缓冲的大小?我必须使用什么方法来做到这一点?请给我更多提示。我是 OpenGL ES 编程的初学者。
    • 对于帧缓冲区对象(离屏渲染),您需要附加更大的纹理或渲染缓冲区附件并分配存储空间。对于屏幕渲染,我怀疑您不走运 - 您不太可能获得大于设备物理显示的窗口表面。
    【解决方案2】:

    我通过这两个链接解决了这个问题。

    1. OpenGL ES ReadPixels to bitmap From Texture larger than screen
    2. GLES20.glReadPixels gets all zero in android

    重点是……

    1. 为了使Bitmap 大于纹理的显示尺寸,请生成新的帧缓冲区而不是使用默认缓冲区。默认缓冲区不大于设备的显示分辨率。
    2. 在初始化 OpenGL ES 的同一 Context 中调用 glReadPixels

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多