采集到的纹理画面如果跟预览的SurfaceView宽高不相同,如果不采取措施,把纹理直接绘制到Surface上,就会导致画面被压缩。
有两种方法解决这个问题,下面是第一种方法:
float textureAspectRatio = (float)texHeight / (float)texWidth;
float viewAspectRatio = (float)screenHeight / (float)screenWidth;
float xOffset = 0.0f;
float yOffset = 0.0f;
if(textureAspectRatio > viewAspectRatio){
//Update Y Offset
int expectedHeight = (int)((float)texHeight*screenWidth/(float)texWidth+0.5f);
yOffset = (float)(expectedHeight-screenHeight)/(2*expectedHeight);
} else if(textureAspectRatio < viewAspectRatio){
//Update X Offset
int expectedWidth = (int)((float)(texHeight * screenWidth) / (float)screenHeight + 0.5);
xOffset = (float)(texWidth - expectedWidth)/(2*texWidth);
}
GLfloat texCoords[] = { xOffset, 1.0f - yOffset, 1.0f - xOffset, 1.0f - yOffset, xOffset, yOffset,
1.0f - xOffset, yOffset };
glVertexAttribPointer(mGLTextureCoords, 2, GL_FLOAT, 0, 0, texCoords);
思路就是把纹理拉伸到跟屏幕等宽或者等高,然后将多余的部分进行裁剪。
第二种方法:
float texWH = (float)width / (float)height;
float screenWH = (float)outputWidth / (float)outputHeight;
bool cut = fabs(texWH - screenWH) <= (9.0f / 16.0f) - (9.0f / 20.0f);
if (cut) {
if(texWH < screenWH){
x_scale = 1.0f;
y_scale = screenWH / texWH;
}else if(texWH > screenWH){
x_scale = texWH / screenWH;
y_scale = 1.0f;
}else{
x_scale = 1.0f;
y_scale = 1.0f;
}
} else {
if(texWH > screenWH){
x_scale = 1.0f;
y_scale = screenWH / texWH;
}else if(texWH < screenWH){
x_scale = texWH / screenWH;
y_scale = 1.0f;
}else{
x_scale = 1.0f;
y_scale = 1.0f;
}
}
下面是vertexShader部分
static const char * vs = STR(
attribute vec2 position;
attribute vec2 texcoord;
uniform float x_scale;
uniform float y_scale;
varying vec2 tx;
void main(){
tx = vec2(texcoord.x, texcoord.y);
vec2 xy = vec2(position.x * x_scale, position.y * y_scale);
gl_Position = vec4(xy, 0, 1.0);
}
);
下面是fragmentShader部分
static const char * fs = STR(
precision mediump float;
varying vec2 tx;
uniform sampler2D tex;
void main(void){
gl_FragColor = texture2D(tex, tx);
}
);
fragmentShader的渲染范围是0到1,如果我们将图片拉伸到小于0或者大于1,则不会显示。利用gl的这个特性,将纹理进行裁剪。
网友评论