OpenGL滚动文本触左边界消失问题求解
OpenGL水平滚动文本横幅修复方案
问题
在OpenGL应用中实现水平滚动文本横幅时,文本从右侧平滑进入屏幕显示正常,但当首个字符触碰窗口左边界时,整个文本会消失。需要实现文本平滑移出边界后从右侧重新开始滚动的效果。
问题根源
- 文本宽度未计算:当前用固定值
-200判断重置位置,没有考虑文本实际宽度,导致文本未完全移出就触发重置,或因光栅位置超出裁剪区而停止绘制。 - 颜色值错误:
glColor4f/glColor3f的参数需为0.0-1.0的浮点数,原代码中173.0f、255.0f会被截断为1.0,颜色显示异常。 - 矩阵设置不完整:
reshape函数未切换回模型视图矩阵并重置,可能导致坐标转换混乱。
修复步骤
- 新增计算文本宽度的函数,准确获取字符串的像素宽度。
- 修改滚动终止条件:当文本完全移出左边界(文本右边缘 < 窗口左边界)时,才将文本重置到窗口右侧。
- 修正颜色值为0.0-1.0的范围。
- 完善
reshape函数的矩阵设置,确保模型视图矩阵正确初始化。
修改后的完整代码
#include <stdio.h> #include <string.h> #include <math.h> #include <iostream> #ifdef WIN32 #include <windows.h> #endif #include <GL/gl.h> #include <GL/glut.h> using namespace std; int state = 1; float xsize = 800; float ysize = 300; const char* scrollText = "Testing train application for windows!!@@"; // 计算文本的像素宽度 float calculateTextWidth(const char* text) { float width = 0.0f; while (*text) { width += glutBitmapWidth(GLUT_BITMAP_TIMES_ROMAN_24, *text); text++; } return width; } void print_bitmap_string(const char* s) { while (*s) { glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *s); s++; } } void reshape(int w, int h) { GLdouble size; GLdouble aspect; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); size = (GLdouble)((w >= h)? w : h) / 2.0; if (w <= h) { aspect = (GLdouble)h / (GLdouble)w; glOrtho(-size, size, -size * aspect, size * aspect, -100000.0, 100000.0); } else { aspect = (GLdouble)w / (GLdouble)h; glOrtho(-size * aspect, size * aspect, -size, size, -100000.0, 100000.0); } glScaled(aspect, aspect, 1.0); // 切换回模型视图矩阵并重置 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } float x_pos = xsize/2; float y_pos = 70; float textWidth = 0.0f; void draw() { glPushMatrix(); glTranslatef(0.5, -100, 0); // 修正颜色值为0-1范围 glColor4f(0.0f, 173.0f/255.0f, 115.0f/255.0f, 1.0f); glRasterPos2f(x_pos, y_pos); print_bitmap_string(scrollText); glPopMatrix(); } void display(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); draw(); // 修正颜色值 glColor3f(0.0f, 1.0f, 0.0f); glutSwapBuffers(); } void timer(int) { glutPostRedisplay(); glutTimerFunc(1000 / 90, timer, 0); switch (state) { case 1: // 当文本完全移出左边界时重置 if (x_pos + textWidth > -xsize / 2) { x_pos -= 1; } else { x_pos = xsize / 2; } break; } } int main(int argc, char** argv) { glutInitWindowSize(xsize, ysize); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutCreateWindow("Train Display"); // 初始化文本宽度 textWidth = calculateTextWidth(scrollText); glutDisplayFunc(display); glutReshapeFunc(reshape); glutTimerFunc(1000 / 90, timer, 0); glutMainLoop(); return 0; }
说明
calculateTextWidth函数遍历字符串,累加每个字符的宽度,得到文本总宽度。- 滚动判断条件改为
x_pos + textWidth > -xsize/2,确保文本完全移出左边界后才重置到右侧。 - 颜色值调整为除以255后的浮点数,保证颜色正确显示。
- 修正了
reshape函数的矩阵切换,避免坐标转换错误。 - 简化了状态机逻辑,去掉不必要的
state=-1分支,直接在条件满足时重置位置。
内容的提问来源于stack exchange,提问作者Gillian De Buyser
相关产品推荐
相关产品推荐

