通过OpenGL ES混合模式缩放视频缓冲区来适应显示尺
当开发基于软件模式的游戏时,通过缩放视频缓冲区来适应显示尺寸是最棘手的问题之一。当面对众多不同的分辨率时(比如开放环境下的Android),该问题会变得更加麻烦,作为开发人员,我们必须尝试在性能与显示质量之间找到最佳平衡点。正如我们在第2章中看到的,缩放视频缓冲区从最慢到最快共有3种类型。
软件模拟:3中类型中最慢,但最容易实现,是没有GPU的老款设备上的最佳选择。但是现在大部分智能手机都支持硬件加速。
混合模式:这种方式混合使用软件模拟(创建图像缓冲区)和硬件渲染(向显示屏绘制)两种模式。这种方法速度很快,而且可以在分辨率大于256×256的任意屏幕上渲染图像。
硬件加速模式:3种类型中最快,但最难实现。这取决于游戏的复杂程度,需要更加强劲的GPU。如果有好的硬件,这种方法就可以创造出令人震撼的质量和效果。但在终端设备比较分裂的平台上,比如Android,这将是十分艰难的选择。
这里,我们选择第二种方式,也是在终端设备分裂的平台上的最佳选择。你拥有软件渲染器,并希望将游戏适配到任意分辨率的显示屏上。此方法非常适合模拟器游戏、街机游戏、简单的射击游戏等。它在各种低端、中端、高端设备上都表现很好。
下面我们开始介绍混合模式并探讨为什么这种方法更加可行。然后,将深入研究这种方法的实现,包括如何初始化surface并通过实际缩放来绘制到纹理。
1. 为什么使用混合缩放
这种缩放技术背后的原理很简单:
你的游戏根据给定的尺寸创建图像缓冲区(通常采用像素格式RGB565,即移动设备最常用的格式)。例如320×240,这是典型的模拟器尺寸。
当一张分辨率为320×240的图像需要被缩放至平板电脑的尺寸(1024×768)或其他任意相同屏幕的设备时,我们可以使用软件模拟的方式来完成缩放,但会慢的令人无法忍受。而采用混合模式进行缩放,需要创建OpenGL ES纹理并将图片(320×240)渲染到GL四边形上。
纹理会通过硬件被缩放到适合显示屏的尺寸(1024×768),从而你的游戏性能将得到显著提升。
从实现的角度看,这个过程可描述如下:
初始化OpenGL ES纹理:在游戏视频被初始化的阶段,必须创建硬件surface。其中包含简单的纹理,要显示的视频图像会被渲染至到该纹理(详见代码清单1与代码清单2)。
将图像缓冲区绘制到纹理:在游戏循环的末端,渲染要显示的视频图像到纹理,该纹理会自动缩放至适合显示屏的尺寸(详见代码清单3)。
代码清单1 创建RGB656格式的空纹理
<SPAN style="FONT-SIZE: 14px">// 纹理ID
static unsigned int mTextureID;
// 被用来计算图片绘制在纹理上的X、Y偏移量
static int xoffset;
static int yoffset;
/**
* 创建RGB565格式的空纹理
* 参数: (w,h) 纹理的宽, 高
* (x_offsety_offset): 图片绘制在纹理上的X、Y偏移量
*/
static void CreateEmptyTextureRGB565 (int w, int h, int x_offset, int y_offset)
{
int size = w * h * 2;
xoffset = x_offset;
yoffset = y_offset;
// 缓冲区
unsigned short * pixels = (unsigned short *)malloc(size);
memset(pixels, 0, size);
// 初始化GL状态
glDisable(GL_DITHER);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glClearColor(.5f, .5f, .5f, 1);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// 创建纹理
glGenTextures(1, &mTextureID);
glBindTexture(GL_TEXTURE_2D, mTextureID);
// 纹理参数
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// RGB565格式的纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_
SHORT_5_6_5 , pixels);
free (pixels);
} </SPAN>
代码清单2展示了CreateEmptyTextureRGB565的实现过程,创建RGB656格式的空纹理用于绘制,参数如下:
w和h:要显示的视频图片的尺寸。
x_offset和y_offset:坐标系中X轴、Y轴的偏移量,视频图片将会按照这个坐标被渲染到纹理。但是为什么我们需要这些参数?请继续阅读。
在OpenGL中创建纹理,我们只需要调用:
软件模拟:3中类型中最慢,但最容易实现,是没有GPU的老款设备上的最佳选择。但是现在大部分智能手机都支持硬件加速。
混合模式:这种方式混合使用软件模拟(创建图像缓冲区)和硬件渲染(向显示屏绘制)两种模式。这种方法速度很快,而且可以在分辨率大于256×256的任意屏幕上渲染图像。
硬件加速模式:3种类型中最快,但最难实现。这取决于游戏的复杂程度,需要更加强劲的GPU。如果有好的硬件,这种方法就可以创造出令人震撼的质量和效果。但在终端设备比较分裂的平台上,比如Android,这将是十分艰难的选择。
这里,我们选择第二种方式,也是在终端设备分裂的平台上的最佳选择。你拥有软件渲染器,并希望将游戏适配到任意分辨率的显示屏上。此方法非常适合模拟器游戏、街机游戏、简单的射击游戏等。它在各种低端、中端、高端设备上都表现很好。
下面我们开始介绍混合模式并探讨为什么这种方法更加可行。然后,将深入研究这种方法的实现,包括如何初始化surface并通过实际缩放来绘制到纹理。
1. 为什么使用混合缩放
这种缩放技术背后的原理很简单:
你的游戏根据给定的尺寸创建图像缓冲区(通常采用像素格式RGB565,即移动设备最常用的格式)。例如320×240,这是典型的模拟器尺寸。
当一张分辨率为320×240的图像需要被缩放至平板电脑的尺寸(1024×768)或其他任意相同屏幕的设备时,我们可以使用软件模拟的方式来完成缩放,但会慢的令人无法忍受。而采用混合模式进行缩放,需要创建OpenGL ES纹理并将图片(320×240)渲染到GL四边形上。
纹理会通过硬件被缩放到适合显示屏的尺寸(1024×768),从而你的游戏性能将得到显著提升。
从实现的角度看,这个过程可描述如下:
初始化OpenGL ES纹理:在游戏视频被初始化的阶段,必须创建硬件surface。其中包含简单的纹理,要显示的视频图像会被渲染至到该纹理(详见代码清单1与代码清单2)。
将图像缓冲区绘制到纹理:在游戏循环的末端,渲染要显示的视频图像到纹理,该纹理会自动缩放至适合显示屏的尺寸(详见代码清单3)。
代码清单1 创建RGB656格式的空纹理
复制代码代码如下:
<SPAN style="FONT-SIZE: 14px">// 纹理ID
static unsigned int mTextureID;
// 被用来计算图片绘制在纹理上的X、Y偏移量
static int xoffset;
static int yoffset;
/**
* 创建RGB565格式的空纹理
* 参数: (w,h) 纹理的宽, 高
* (x_offsety_offset): 图片绘制在纹理上的X、Y偏移量
*/
static void CreateEmptyTextureRGB565 (int w, int h, int x_offset, int y_offset)
{
int size = w * h * 2;
xoffset = x_offset;
yoffset = y_offset;
// 缓冲区
unsigned short * pixels = (unsigned short *)malloc(size);
memset(pixels, 0, size);
// 初始化GL状态
glDisable(GL_DITHER);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glClearColor(.5f, .5f, .5f, 1);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// 创建纹理
glGenTextures(1, &mTextureID);
glBindTexture(GL_TEXTURE_2D, mTextureID);
// 纹理参数
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// RGB565格式的纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_
SHORT_5_6_5 , pixels);
free (pixels);
} </SPAN>
代码清单2展示了CreateEmptyTextureRGB565的实现过程,创建RGB656格式的空纹理用于绘制,参数如下:
w和h:要显示的视频图片的尺寸。
x_offset和y_offset:坐标系中X轴、Y轴的偏移量,视频图片将会按照这个坐标被渲染到纹理。但是为什么我们需要这些参数?请继续阅读。
在OpenGL中创建纹理,我们只需要调用:
复制代码代码如下: