1. 问题现象与背景分析
在Android平台上使用Camera2 API结合OpenGL ES进行相机预览时,开发者经常会遇到一个棘手的问题:当设备在竖屏(Portrait)和横屏(Landscape)模式之间切换时,预览画面会出现"轻微拉伸"的失真现象。这种拉伸通常表现为图像比例失调,比如人脸看起来变胖或变瘦,圆形物体变成椭圆形等。
这个问题之所以普遍存在,根源在于Camera2 API的输出图像特性与OpenGL ES渲染管线的配合出现了错位。具体来说:
- 相机传感器本身有固定的物理方向(通常是横屏方向)
- 设备屏幕可以自由旋转
- OpenGL的视口(Viewport)和投影矩阵需要动态调整
- 图像数据的宽高比与显示表面的宽高比可能不一致
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心原因深度解析
2.1 相机传感器方向与屏幕方向的矛盾
现代Android设备的相机传感器通常是按照横屏(Landscape)方向固定的。这意味着:
- 即使你竖着拿手机,传感器输出的图像数据仍然是横屏方向的
- 系统会自动对图像进行旋转(通过EXIF中的orientation标签)
- 但原始图像数据的宽高比仍然是传感器的物理宽高比
2.2 OpenGL视口配置问题
在OpenGL渲染管线中,有几个关键因素会影响最终显示效果:
- 视口(viewport)设置:通过glViewport()设置的绘制区域
- 投影矩阵:决定3D空间如何映射到2D屏幕
- 纹理坐标:相机图像作为纹理贴图时的映射关系
常见的错误做法是简单地将视口设置为SurfaceView的当前尺寸,而没有考虑图像原始宽高比。
2.3 矩阵变换链的缺失
完整的渲染管线应该包含以下变换步骤:
- 模型矩阵(处理物体本身的变换)
- 视图矩阵(相机位置和方向)
- 投影矩阵(3D到2D的投影)
- 视口变换(到屏幕坐标)
大多数拉伸问题都源于投影矩阵和视口变换没有正确考虑图像宽高比。
3. 完整解决方案实现
3.1 获取相机特性参数
首先需要从CameraCharacteristics中获取关键信息:
java复制CameraManager manager = (CameraManager) context.get
