OpenGL и Camera Preview - предварительно умноженное альфа - смешивание дает "насыщенный" цвет

Хорошо, вот моя проблема с OpenGL, которую я действительно не могу исправить. Все отлично работает на Galaxy S1 и на 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;
    }
}

GameRenderer:

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 ответ

Решение

Хорошо, я получил ответ за это. Проблема заключалась в предварительном умножении значений альфа. Поэтому проще всего написать:

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, где я не могу написать свой собственный шейдерный код. Надеюсь, это поможет всем, у кого такая же проблема! Спасибо, Тобиас

Другие вопросы по тегам