2D游戏引擎中如何实现不受分辨率与宽高比影响的固定全局缩放
2D游戏引擎固定全局缩放实现方案
现有方案的核心偏差
- 初始缩放公式直接绑定屏幕宽高,会导致非1:1宽高比下正方形对象被拉伸变形,无法维持恒定的视觉占比
- 宽高比参数没有和投影层的坐标映射逻辑绑定,导致不同分辨率下的对象尺度计算出现偏差
- 初始公式直接将屏幕像素长度乘入对象缩放值,混合了世界空间与像素空间的职责边界,会在投影校正时出现双重缩放,且x、y轴缩放比例不匹配宽高比,直接把正方形拉变形
- 缩放计算没有做职责分层,后续窗口缩放调整时容易出现错位
宽高比参数的正确引入位置
宽高比参数不需要塞入单个对象的缩放计算公式,应该在全局正交投影矩阵生成的前置环节引入,原因是投影矩阵才是负责把世界坐标映射到屏幕像素的核心层,对象缩放只需要处理世界空间内的相对尺寸即可。
具体实现时的尺度对齐逻辑:
- 要实现恒定5%的屏幕占比,不能按屏幕宽度或者高度的5%计算长度基准,必须取**屏幕短边的5%**作为1个世界单位的实际可视长度。这样无论屏幕是16:9、4:3还是其他比例,1x1的正方形对象在屏幕上的视觉大小完全一致,不会出现拉伸
- 宽高比的作用只是用来扩展长边方向的可视范围,不会修改短边的长度基准:
- 宽屏(宽>高):垂直方向的可视范围固定匹配短边长度,水平方向按照宽高比等比例扩展可视宽度
- 竖屏(高>宽):水平方向的可视范围固定匹配短边长度,垂直方向按照宽高比等比例扩展可视高度
纹理无裁切的保障措施
只要满足以下两个配置,搭载16x16/32x32纹理的1x1对象,无论怎么缩放都不会出现裁切:
- 顶点与UV严格对齐:1x1规格的正方形对象,顶点范围设置为
(-0.5, -0.5)到(0.5, 0.5),正好覆盖1个世界单位的完整范围,对应的UV坐标从(0,0)到(1,1)完全匹配,没有偏移或者截断 - 纹理采样配置正确:
- 纹理环绕模式设置为
GL_CLAMP_TO_EDGE,避免重复采样导致的边缘内容错位 - 开启线性采样和mipmap生成,大比例缩放时自动平滑纹理,不会出现边缘漏边或者裁切
- 纹理环绕模式设置为
可直接落地的参考代码
投影矩阵生成(宽高比引入环节)
// 实时获取屏幕参数 float aspect_ratio = (float)SCREEN_WIDTH / (float)SCREEN_HEIGHT; float screen_short_side = std::min(SCREEN_WIDTH, SCREEN_HEIGHT); // 定义1个世界单位对应屏幕短边的5% float unit_visual_length = screen_short_side * 0.05f; // 计算正交投影的可视范围 float visible_half_width, visible_half_height; if (aspect_ratio >= 1.0f) { visible_half_height = unit_visual_length * 0.5f / 0.05f; visible_half_width = visible_half_height * aspect_ratio; } else { visible_half_width = unit_visual_length * 0.5f / 0.05f; visible_half_height = visible_half_width / aspect_ratio; } // 生成最终正交投影矩阵 glm::mat4 projection = glm::ortho( -visible_half_width, visible_half_width, -visible_half_height, visible_half_height, -1.0f, 1.0f );
对象缩放计算不需要再乘屏幕尺寸,直接使用传入的in_scale作为out_scale即可——因为投影层已经把1个世界单位的可视长度固定为屏幕短边的5%。
纹理加载配置(防裁切)
// 绑定纹理后设置参数 glBindTexture(GL_TEXTURE_2D, texture_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 生成mipmap保障缩放时纹理完整 glGenerateMipmap(GL_TEXTURE_2D);
窗口创建和视口设置的现有代码逻辑是正确的,只需要在窗口尺寸变化的回调里,重新调用
glViewport(0, 0, new_width, new_height)、更新屏幕参数、重新生成上面的投影矩阵即可。
内容的提问来源于stack exchange,提问作者John_Kadar
相关产品推荐
相关产品推荐

