openGL控制FPS (每秒传输的帧数)
前言
在openGL中渲染场景,经常用到单缓冲、双缓冲技术,提高或者降低FPS,以达到某种特效。比方说:
场景1:场景中有一团烟雾,在微风的情况下,烟雾袅袅升起,随风慢慢飘摇
场景2:场景中有一团烟雾,在大风的情况下,烟雾喷涌而出,随风瞬间飘散
如果这两种情况都用同样的FPS,效果就是一样的,无法区分。所有我们需要控制FPS
详解
1.现象
GLUT_SINGLE 指定单缓存窗口
GLUT_DOUBLE 指定双缓存窗口
应用程序使用单缓冲绘图时可能会存在图像闪烁的问题。 这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,由上而下逐像素地绘制而成的。最终图像不是在瞬间显示给用户,而是通过一步一步生成的,这会导致渲染的结果很不真实。为了规避这些问题,我们应用双缓冲渲染窗口应用程序。前缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在后缓冲上绘制。当所有的渲染指令执行完毕后,我们交换(Swap)前缓冲和后缓冲,这样图像就立即呈显出来,之前提到的不真实感就消除了。
2、原理
GLUT_SINGLE单缓冲,屏幕显示调用glFlush(),将图像在当前显示缓存中直接渲染,会有图形跳动(闪烁)问题
GLUT_DOUBLE双缓冲,屏幕显示调用glutSwapBuffers(),将图像先绘制在另外的缓存中,渲染完毕之后,将其整个缓存贴到当前的窗口,能消除闪烁,一般动画要用双缓冲.
如果缓冲与函数不对应的话,则会出错。
所谓双缓冲技术,是指两个缓冲区:前台缓冲和后台缓冲。前台缓冲即我们看到的屏幕,
后台缓冲则在内存当中,对我们来说是不可见的。每次我们绘图都在后台缓冲中进行的,
当绘图完成时,就必须把绘制的最终结果复制到屏幕上。在opengl中glutSwapBuffers函数就
可以实现双缓冲技术的一个重要函数。该函数的作用就是交换两个缓冲区的指针,从而把绘制
结果图复制到屏幕上,从而使用户可见。否则在后台缓冲中,使得绘图结果不可见。
那么在程序中怎么使用双缓冲呢?
一般在main函数中开启双缓冲,主要是调用glutInitDisplayMode函数,该函数的功能是设
置初始显示模式。函数原型:void glutInitDisplayMode(unsigned int mode);里面的
mode可以取一下值或其组合:
其中里面就有一个双缓存窗口。
开启双缓冲之后就要用函数glutSwapBuffers()函数以及来交换两个缓冲区
指针。此函数一般用于绘制操作完成后。在main函数中用glutDisplayFunc
函数注册一个绘图函数就可以调用绘图函数,从而就可以调用双缓冲交换函数。
编码
使用glutSwapBuffers()函数可以实现双缓冲效果,但是并不能控制FPS,依然不能满足我们的需求,这时就需要用到glutPostRedisplay();和glutIdleFunc(idelFunc);以及glutTimerFunc(16, OnTimer, 1);
先看下烟雾效果
//添加定时器glutTimerFunc(16, OnTimer, 1);glutIdleFunc(idelFunc);glutSwapBuffers(); // 交换缓存 glutPostRedisplay();
主要代码
// SmokeSimulate.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
// 包含有关OpenGL函数的头文件
//#include "GL/GL.H"
//#include "GL/GLU.h"
//#include "GL/GLAUX.H"
//#include "GL/glut.h"
//#include <iostream>//#include <iostream>
//#include <Windows.h>
#include "tools.h"
#include "Grids.h"
#include "3dmap.h"
#include "xFreeTypeLib.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"#define SMOKEX 32
#define SMOKEY 32typedef struct {float r;float g;float b;
} COL;GLuint mainWindow = 0;
GLuint alpha = 0;
GLuint nearPlane = -1000;
GLuint farPlane = 1920;float deltaTime = 0.0f;
float lastFrame = 0.0f;
const float fps = 60.0f;
float msPerFrame = 1.0f / fps;/
bool RenderScene();
int InitGL(GLvoid);
void Fuoco(void);
void ShowSmoke(float x, float y, float z, float dim);
COL Colore(float k);
void OnTimer(int value);
void idelFunc(); //空闲函数bool freeze;
int frame;
GLuint Texture[1];
unsigned char Bsmoke[SMOKEX][SMOKEY];int xFar = 0.0f, yFar = 0.0f, zFar = 0.0f;
int wWidth = 1366, wHeight = 768;
int oldX, oldY;
bool gIsStartTrackBall = false;
bool gIsMoveMap = false;
TrackBall trackball;
_3dMap map;xFreeTypeLib g_FreeTypeLib;
float ratio;
//wchar_t g_UnicodeString[]=L"aaabb/x4E2D/x6587/x0031/x0032/x0033";
const char g_UnicodeString[] = "0 1 2 3 4 5 6 时间(天)\" ";
const char g_UnicodeStringScript[] = "-10 0 10 20 30 40 50 \" ";
const char g_UnicodeStringScriptHz[] = "0 1000 2000 3000 4000 5000 频率(MHz)\" ";
const char g_UnicodeStringScriptLevel[] = "0 1000 2000 3000 4000 5000 能量电平(Db)\" ";extern stuxCharTexture g_TexID[65536];LPWSTR AnsiToUnicode(LPCSTR lpcstr);
void drawText(wchar_t* _strText, int x, int y, int maxW, int h);void displayEvent()
{//烟雾相关RenderScene();//glFlush();glutSwapBuffers(); // 交换缓存
}void mouseMoveEvent(int x, int y)
{if (gIsStartTrackBall){trackball.MouseMove(x, y);//glutPostRedisplay();glutSetWindow(mainWindow);//glutPostRedisplay();}if (gIsMoveMap){xFar -= oldX - x;yFar += oldY - y;oldX = x;oldY = y;//glutPostRedisplay();}
}void idelFunc()
{float currentFrame = GetTickCount() * 0.1f;deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;//checkCollision();if (deltaTime > msPerFrame){displayEvent();}
}// 鼠标事件函数
void mouseEvent(int button, int state, int x, int y)
{if (state == GLUT_UP && button == GLUT_WHEEL_UP) //鼠标滚轮{zFar -= 80;//glutPostRedisplay();}if (state == GLUT_UP && button == GLUT_WHEEL_DOWN){zFar += 80;//glutPostRedisplay();}if (button == GLUT_LEFT_BUTTON){if (state == GLUT_DOWN){oldX = x;oldY = y;trackball.setXY(x, y);gIsStartTrackBall = true;}else if (state == GLUT_UP){oldX = x;oldY = y;gIsStartTrackBall = false;}//glutPostRedisplay();}else if (button == GLUT_RIGHT_BUTTON){if (state == GLUT_DOWN){oldX = x;oldY = y;gIsMoveMap = true;}else if (state == GLUT_UP){oldX = x;oldY = y;gIsMoveMap = false;}}
}
// 窗体尺寸变化事件
void resizeEvent(int w, int h)
{/
//添加窗口缩放时的图形变换函数glViewport(0, 0, w, h);/glMatrixMode(GL_PROJECTION); // 选择投影矩阵glLoadIdentity(); // 设置投影矩阵// 根据窗口的比例设置变换gluPerspective(45.0f, (GLfloat)w / (GLfloat)h, 0.01f, 1000.0f);//glOrtho(0, 0, w, h, nearPlane, farPlane);glMatrixMode(GL_MODELVIEW); // 选择模型矩阵glLoadIdentity(); // 设置模型矩阵gluLookAt(0.0f, 0.0f, 10.0f, 0.0f, -10.0f, 0.0f, 0.0f, 1.0f, 0.0f); //为什么没效果//glutPostRedisplay();}
void processSpecialKeys(int key, int x, int y) {if (key == 101){zFar += 4;//glutPostRedisplay();}if (key == 103){//zFar -= 4;//glutPostRedisplay();}printf("key:%d\n", key);
}void MenuFunc(int data)
{switch (data){case 1:map.setLineOrFill(); break;default:break;}//glutPostRedisplay();
}
void glInit()
{glShadeModel(GL_FLAT);//SMOOTH//GL_FLATglClearColor(1.0f, 1.0f, 1.0f, 0.5f);glClearDepth(1.0f);glEnable(GL_NORMALIZE);glEnable(GL_DEPTH_TEST);glAlphaFunc(GL_GREATER, 0);glDepthFunc(GL_LEQUAL);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);/*glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/glEnable(GL_POINT_SMOOTH);glEnable(GL_LINE_SMOOTH);glEnable(GL_POLYGON_SMOOTH);glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Make round points, not square pointsglHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Antialias the linesglHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);//glClearColor(1.0f,1.0f,1.0f,0.5f); //窗口背景设置为白色glMatrixMode(GL_MODELVIEW); //设置投影参数glEnable(GL_COLOR_MATERIAL);glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);//g_FreeTypeLib.load("simhei.ttf",14,14); // g_FreeTypeLib.load("c://windows//fonts//simhei.ttf",14,14); g_FreeTypeLib.load("c://windows//fonts//simhei.ttf", 12, 12);//烟雾InitGL();//glDisable(GL_CULL_FACE);//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); }xCharTexture* getTextChar(wchar_t ch)
{g_FreeTypeLib.loadChar(ch);return &g_TexID[ch];
}LPWSTR AnsiToUnicode(LPCSTR lpcstr) //参数lpcstr类型也可是char*
{LPWSTR Pwstr;int i;i = MultiByteToWideChar(CP_ACP, 0, lpcstr, -1, NULL, 0);Pwstr = new WCHAR[i];MultiByteToWideChar(CP_ACP, 0, lpcstr, -1, Pwstr, i);return (Pwstr);
}void drawText(wchar_t* _strText, int x, int y, int maxW, int h)
{int sx = x;int sy = y;int maxH = h;size_t nLen = wcslen(_strText);for (int i = 0; i < nLen; i++){if (_strText[i] == '/n'){sx = x; sy += maxH + 12;continue;}xCharTexture* pCharTex = getTextChar(_strText[i]);glBindTexture(GL_TEXTURE_2D, pCharTex->m_texID); //绑定到目标纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glEnable(GL_BLEND);glDepthMask(GL_TRUE);//打开或关闭OpenGL的特殊功能 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //特殊的像素算法 //glBlendFunc(GL_ONE, GL_ZERO);glEnable(GL_TEXTURE_2D); //去透明int w = pCharTex->m_Width;int h = pCharTex->m_Height;int ch_x = sx + pCharTex->m_delta_x;int ch_y = sy - h - pCharTex->m_delta_y;if (maxH < h) maxH = h;glBegin(GL_QUADS); // 定义一个或一组原始的顶点 {glTexCoord2f(0.0f, 1.0f); glVertex3f(ch_x, ch_y, 1.0f);glTexCoord2f(1.0f, 1.0f); glVertex3f(ch_x + w, ch_y, 1.0f);glTexCoord2f(1.0f, 0.0f); glVertex3f(ch_x + w, ch_y + h, 1.0f);glTexCoord2f(0.0f, 0.0f); glVertex3f(ch_x, ch_y + h, 1.0f);}glEnd();sx += pCharTex->m_adv_x;if (sx > x + maxW){sx = x; sy += maxH + 12;}}
}//
// 场景绘制与渲染
//
bool RenderScene()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();frame++;frame = frame % 2;if (frame == 0){if (freeze == false)Fuoco(); // 生成烟雾}glTranslatef(0.1f, 0.0f, -2.7f);ShowSmoke(0, 0, 0, (float)0.2); // 显示烟雾//::SwapBuffers(m_pDC->GetSafeHdc()); // 交互缓冲区//glFlush();//glutPostRedisplay();//glutSwapBuffers(); // 交换缓存 /*glutSetWindow(mainWindow);glutPostRedisplay();*///glutPostRedisplay();//glFlush();//glutSwapBuffers(); // 交换缓存 return true;
}COL Colore(float k)
{COL c;// if( k<64 )// {// c.r=k/64;// c.g=k/64;// c.b=k/64;// }// else// {if (k < 128){c.r = k / 128;c.g = k / 128;c.b = k / 128;}else{if (k < 192){c.r = k / 256;c.g = k / 256;c.b = k / 256;}else{c.r = 1;c.g = 1;c.b = 1;}}// }return(c);
}void ShowSmoke(float x, float y, float z, float dim)
{float xi, yi;float ka, kb, kc, kd;COL col;int xd, yd;yi = y + dim * SMOKEY / 2;for (yd = 0; yd < SMOKEY - 1; yd++){xi = x - dim * SMOKEX / 2;for (xd = 1; xd < SMOKEX - 1; xd++){ka = (float)Bsmoke[xd][yd];kb = (float)Bsmoke[xd + 1][yd];kc = (float)Bsmoke[xd + 1][yd + 1];kd = (float)Bsmoke[xd][yd + 1];glBegin(GL_QUADS); // 绘制四边形col = Colore(kd);glColor3f(col.r, col.g, col.b);glVertex3f(xi, yi, z);col = Colore(kc);glColor3f(col.r, col.g, col.b);glVertex3f(xi + dim, yi, z);col = Colore(kb);glColor3f(col.r, col.g, col.b);glVertex3f(xi + dim, yi + dim, z);col = Colore(ka);glColor3f(col.r, col.g, col.b);glVertex3f(xi, yi + dim, z);glEnd();xi += dim;}yi -= dim;}
}void Fuoco(void)
{int x, y;int k;for (x = 8; x < SMOKEX - 8; x++)Bsmoke[x][SMOKEY - 1] = rand() % 192;for (x = 0; x < 5; x++)Bsmoke[rand() % SMOKEX][SMOKEY - 1] = 0;for (y = 0; y < SMOKEY - 1; y++){for (x = 1; x < SMOKEX - 1; x++){k = Bsmoke[x][y] + Bsmoke[x - 1][y + 1] + Bsmoke[x + 1][y + 1] + Bsmoke[x][y + 1];k = k / 4 - 2;if (k < 0)k = 0;Bsmoke[x][y] = (unsigned char)k;}}
}int InitGL(GLvoid)
{glShadeModel(GL_SMOOTH);glClearColor(0.0f, 0.0f, 0.0f, 0.5f);glClearDepth(1.0f);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);for (int y = 0; y < SMOKEY; y++){for (int x = 0; x < SMOKEX; x++)Bsmoke[x][y] = 0;}freeze = false;frame = 0;return TRUE;
}void OnTimer(int value)
{/*alpha++;alpha = (alpha % 256);*///displayEvent();glutPostRedisplay();glutTimerFunc(16, OnTimer, 1);
}int main(int argc, char* argv[])
{//ANSI字符串,内容长度7字节 char sz[20] = "中文123";//UNICODE字符串,内容长度5个wchar_t(10字节) wchar_t wsz[100] = L"/x4E2D/x6587/x0031/x0032/x0033";//运行时设定当前ANSI编码,VC格式 setlocale(LC_ALL, ".936");//GCC中格式 setlocale(LC_ALL, "zh_CN.GBK");//VisualC++中使用小写%s,按照setlocale指定编码输出到文件 //GCC中使用大写%S //把UNICODE字符串按照setlocale指定的编码转换成字节 wcstombs(sz, wsz, 20);//把字节串按照setlocale指定的编码转换成UNICODE字符串 mbstowcs(wsz, sz, 20);map.initMap();glutInit(&argc, argv); //初始化GLUTglutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE); //设置显示模式glutInitWindowPosition(0, 0); //设置显示窗口的左上角位置glutInitWindowSize(wWidth, wHeight); //设置窗口的长和高mainWindow = glutCreateWindow("3DMap"); //创造显示窗口glInit(); //开始初始化过程int main_version, sub_version, release_version;const char* version = (const char*)glGetString(GL_VERSION);sscanf(version, "%d.%d.%d", &main_version, &sub_version, &release_version);printf("OpenGL 版本:%s\n", version);printf("主版本号:%d\n", main_version);printf("次版本号:%d\n", sub_version);printf("发行版本号:%d\n", release_version);glutReshapeFunc(resizeEvent); //当窗口尺寸改变时,图形比例不发生变化glutDisplayFunc(displayEvent);glutIdleFunc(idelFunc);glutMouseFunc(mouseEvent);glutSpecialFunc(processSpecialKeys);glutMotionFunc(mouseMoveEvent);//添加定时器glutTimerFunc(16, OnTimer, 1);glutCreateMenu(MenuFunc);glutAddMenuEntry("填充/网格", 1);glutAttachMenu(GLUT_MIDDLE_BUTTON);glutMainLoop(); //显示所有并等候getchar();return 0;
}
工程源码下载地址
openGL控制FPS (每秒传输的帧数)相关推荐
- 神经网络学习小记录72——Parameters参数量、FLOPs浮点运算次数、FPS每秒传输帧数等计算量衡量指标解析
神经网络学习小记录72--Parameters参数量.FLOPs浮点运算次数.FPS每秒传输帧数等计算量衡量指标解析 学习前言 网络的运算时组成 我们要关注网络的什么指标 1.Parameters参数 ...
- 60帧/秒摄像头 视频帧数最佳选择!
随着网络的普及,作为电脑外设产品的摄像头也迅速进入千家万户.这一重大商机也给摄像头行业的发展带来一片繁荣景象.在这个进入门槛低.公模横行的行业,摄像头产品在外观设计.用户应用范围.新功能技术指标等方面 ...
- fps 每秒刷新的频率
(1)FPS是指画面的帧数 FPS指画面每秒传输帧数,通俗来讲就是指游戏和动画或视频的画面数,每秒帧数愈多,所显示的动作就会愈流畅,这个值是越高越好,因为越高代表了你每秒帧数就越多,帧数越多,每秒所刷 ...
- [译]GLUT教程 - 每秒帧数
Lighthouse3d.com >> GLUT Tutorial >> Extras >> Frames per Second 你的程序实际上跑得多快? 有时我们 ...
- Unity中帧数FPS的显示查看
Unity中帧数FPS的显示查看 显示帧数 开发测试时的Game视图 开发测试时的Profiler视图 发布后的FPS显示 显示帧数 FPS可以用3中方式查看: 开发测试时的Game视图 如下图显示的 ...
- 安卓流畅度测试方法二:FPS Meter测试安卓帧数
http://pcedu.pconline.com.cn/508/5084799_1.html http://pcedu.pconline.com.cn/508/5084799_1.html http ...
- 画质、码率、帧数、分辨率、体积的基础编码知识
转自:http://support.shangzhibo.tv/hc/kb/article/1028655/ 很多新手对这方面的概念都比较模糊,这是我在网上总结来的有关画质.码率.帧数.分辨率.体积的 ...
- 实时帧数手机_过度营销还是真实刚需?三分钟带你了解手机高刷新率的那些事...
关注机锋网,有趣的科技媒体 对于很多电竞玩家而言,高刷屏幕早已经不是什么新鲜设备 随着前两年"吃鸡"的大火,也间接带动了一波电竞设备的火爆,其中高刷新率屏幕首当其冲,成为了不少高玩 ...
- FPS (每秒传输帧数(Frames Per Second))
FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数.FPS是测量用于保存.显示动态视频的信息数量.每秒钟帧数越多,所显示的动作就会越流畅.通常,要避免动作不流畅的最低是3 ...
最新文章
- Java清空数组的数据
- iptables自定义链增加和删除
- spring整合junit问题分析
- 使用 NVM 管理不同的 Node.js 版本
- 企业应用程序开发框架的分类
- 超图Cesium鼠标事件处理
- postman 字符串中有冒号_【接口测试】Postman入门09 Postman获取HTTP请求
- 2016年2月23日----Javascript运算符
- 是否进行“ git导出”(如“ svn导出”)?
- java.lang.NoSuchMethodError示例
- 我购买了一台acer笔记本
- PMP_考前冲刺题(2022)(3A通过分享)(180题附答案及解析)
- UDP socket编程: C++发送 | C#接收
- QuartusII下载程序报错,无法正常下载
- linux源码编译ipk,OpenWrt-SDK-编译生成ipk软件包
- qcom usb驱动下载_艾肯Mobile Q驱动-艾肯Mobile Q usb外置声卡驱动下载v1.35.20 官方最新版-西西软件下载...
- JavaScript笔记 Object对象
- 萌新小白的HTML第一天学习
- 在线观看视频--使用代码倍速播放
- rs485接口上下拉_详解RS-485上下拉电阻的选择