繁体   English   中英

如何在Android上使用OpenGL ES 2.0渲染大尺寸图像

[英]How to render large size image with OpenGL ES 2.0 on android

我试图在Android操作系统上通过OpenGL ES 2.0更改图像的颜色。 这是我的代码。

Tex类

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×2160这样的高分辨率是不正常的。在渲染图像中,小尺寸和颜色改变的原始图像位于左下角。 其余区域填充黑色。 我不知道出了什么问题。 我必须为高分辨率图像设置一些东西吗? 我需要建议。 请帮忙。

你在渲染什么?

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

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

  1. OpenGL ES ReadPixels to bitmap From Texture大于屏幕
  2. GLES20.glReadPixels在android中全部为零

重点是...

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM