代码之家  ›  专栏  ›  技术社区  ›  Tobias Reich

OpenGL和相机预览-预乘阿尔法-混合在一起会产生过度饱和的颜色

  •  0
  • Tobias Reich  · 技术社区  · 13 年前

    好吧,这是我的OpenGL问题,我真的无法解决。在Galaxy S1和似乎拥有几乎相同GPU的S2上,一切都很好。 但当我尝试制作AR应用程序时,我总是会遇到相机预览顶部透明像素的问题。只有当像素是透明的并且看起来像“燃烧的颜色”或值溢出或类似的情况时,它才会出现。所以,请告诉我我做错了什么,或者如果你有S3,请尝试一下。也许我的刚刚坏了?? 我为您创建了一个小型测试程序。请看一下:

    public class MainActivity extends Activity {
    private GLSurfaceView mGLView;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mGLView = new GLSurfaceView(this);
            mGLView.setEGLContextClientVersion(2);
            mGLView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
            mGLView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
            mGLView.setZOrderOnTop(true);        
            GameRenderer renderer = new GameRenderer();
            mGLView.setRenderer(renderer);
            setContentView(new CameraView(this), new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            addContentView(mGLView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mGLView.onPause();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mGLView.onResume();
        }
    }
    

    CameraView如下所示:

    public class CameraView extends SurfaceView implements SurfaceHolder.Callback{
    
        SurfaceHolder surfaceHolder;
        Camera camera;
    
        public CameraView(Context context, AttributeSet attrs) {
            super(context, attrs);
            surfaceHolder = getHolder();
            surfaceHolder.addCallback(this);
        }
    
        /**
         * @param context
         */
        public CameraView(Context context) {
            super(context);
            surfaceHolder = getHolder();
            surfaceHolder.addCallback(this);
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setPreviewSize(w, h);
                camera.setParameters(parameters);
            } catch (Exception e) {
                Log.w("CameraView", "Exception:" , e);
            }
            camera.startPreview();
        }
    
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            camera = Camera.open();
            try {
                camera.setPreviewDisplay(holder);
            } catch (IOException exception) {
                camera.release();
                camera = null;
            }   
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder arg0) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }
    

    游戏渲染器:

    public class GameRenderer implements GLSurfaceView.Renderer {
    
        private final String vertexShaderCode = 
            "uniform mat4 uMVPMatrix;   \n" +
            "attribute vec4 vPosition;  \n" +
            "void main(){               \n" +
                " gl_Position = uMVPMatrix * vPosition; \n" +
            "}  \n";
    
        private final String fragmentShaderCode = 
            "void main(){                       \n" +
                " gl_FragColor = vec4(1.0, 1.0, 1.0, 0.3); \n" +        
            "}                                  \n";
    
        private int loadShader(int type, String shaderCode){
            int shader = GLES20.glCreateShader(type); 
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);        
            return shader;
        }
    
        // END OF SHADER STUFF
    
        private int mProgram;
        private int maPositionHandle;
        private int muMVPMatrixHandle;
    
        private FloatBuffer triangleVB;
    
        public GameRenderer() {
        }
    
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            GLES20.glClearColor(0,0,0,0); 
            initShapes();
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
            mProgram = GLES20.glCreateProgram();            
            GLES20.glAttachShader(mProgram, vertexShader);  
            GLES20.glAttachShader(mProgram, fragmentShader); 
            GLES20.glLinkProgram(mProgram);              
            maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            GLES20.glUseProgram(mProgram);
            MatrixStack.initStack();
        }
    
        public void onDrawFrame(GL10 unused) {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
            drawGround();    
        }
    
        private void drawGround() {
            GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 0, triangleVB);
            GLES20.glEnableVertexAttribArray(maPositionHandle); 
            Matrix.multiplyMM(MatrixStack.getMVPMatrix(), 0, MatrixStack.getMVMatrix(), 0, MatrixStack.getMVMatrix(), 0);
            Matrix.multiplyMM(MatrixStack.getMVPMatrix(), 0, MatrixStack.getPMatrix(), 0, MatrixStack.getMVPMatrix(), 0);
            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixStack.getMVPMatrix(), 0);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
            GLES20.glDisableVertexAttribArray(maPositionHandle);
        }
    
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
            float ratio = (float) width / height;
            Matrix.frustumM(MatrixStack.getPMatrix(), 0, -ratio, ratio, -1, 1, 1, 1000);
            muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
            Matrix.setLookAtM(MatrixStack.getMVMatrix(), 0,  0, 0,-1,  0, 0, 0,  0, 1, 0);
        }  
    
        private void initShapes(){  
            float triangleCoords[] = {
                -15f, -2f,  15f,
                 15f, -2f,  15f,
                -15f, -2f, -15f,         
                 15f, -2f, -15f
            }; 
            ByteBuffer vbb = ByteBuffer.allocateDirect(triangleCoords.length * 4); 
            vbb.order(ByteOrder.nativeOrder());
            triangleVB = vbb.asFloatBuffer();  
            triangleVB.put(triangleCoords);    
            triangleVB.position(0);            
        }       
    }
    

    还有一个小的MatrixStack类,但我认为这里不会有问题:

    public class MatrixStack {
    
        private static Stack<float[]> matrixStack = new Stack<float[]>();   
    
        private static float[] MVMatrix = new float[16];
        private static float[] PMatrix = new float[16];
        private static float[] MVPMatrix = new float[16];
    
        protected static void initStack(){
            float[] basisMatrix = new float[16];
            Matrix.setIdentityM(basisMatrix, 0);
            matrixStack.push(basisMatrix);
            MVMatrix = basisMatrix;
            Matrix.setIdentityM(PMatrix, 0);
        }
    
        public static float[] getMVMatrix(){
            return MVMatrix; 
        }
    
        public static float[] getPMatrix(){
            return PMatrix; 
        }
    
        public static float[] getMVPMatrix(){
            return MVPMatrix; 
        }
    
    }
    

    好吧,仅此而已。看起来相机预览“过度曝光”了我的gl片段。 请至少尝试此代码。我仍然希望我的手机出了什么问题。 无论如何,谢谢你的帮助, 托比亚斯

    1 回复  |  直到 12 年前
        1
  •  2
  •   Tobias Reich    13 年前

    好吧,我有答案了。 问题是阿尔法值的预乘。 因此,用最简单的方法就足够了:

    vec3 color = clamp(textureColor.rgb * lightWeighting.xyz, 0.0, 1.0);
    color *= 0.5; // premultiply by alpha
    gl_FragColor = vec4(color, 0.5);
    

    尽管我不明白为什么它在旧系统上运行得很好,而且我仍然不确定如何在Gl1.0上管理它,因为我无法编写自己的着色器代码。 所以希望这能帮助到任何有同样问题的人! 谢谢 托比亚斯

    推荐文章