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