在OpenGL中绘制物体的轨迹
Posted
技术标签:
【中文标题】在OpenGL中绘制物体的轨迹【英文标题】:Draw trajectory of an object in OpenGL 【发布时间】:2017-04-02 04:08:52 【问题描述】:当我点击屏幕上的任何位置时,我想制作绘制轨迹的代码。
我将初始中心点设置为起点。我想将单击鼠标按钮的另一点(目标点)设置为变量,但我不知道该怎么做。
float v1[3] = -35.0f, 22.5f, 0.0f ;
float v2[3] = -35.0f, -22.5f, 0.0f ;
float v3[3] = 0.0f, 42.5f, 0.0f ;
float v4[3] = 0.0f, -42.5f, 0.0f ;
float v5[3] = 35.0f, 22.5f, 0.0f ;
float v6[3] = 35.0f, -22.5f, 0.0f ;
这是对象的初始位置。 (6点星,2个三角形)
float px, py;
float center_s[3] = 0.0f, 0.0f, 0.0f ;
float center_d[3] = px, py, 0.0f ;
center_s
是起点,center_d
是终点,变量px
,py
。
void lines(void)
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex3fv(center_s);
glLineWidth(1);
glBegin(GL_LINES);
glVertex3fv(center_s);
glVertex3fv(center_d);
此函数用红线绘制从center_s
到center_d
的轨迹。它还绘制了一个中心点。
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
x = mx;
y = glutGet(GLUT_WINDOW_HEIGHT) - my;
px = x + 35.0;
py = y + 42.5;
glutIdleFunc(lines);
glutPostRedisplay();
break;
这就是问题所在。当按下鼠标左键时,星星必须移动到单击的位置并计算位置的中心点并绘制线。但是如果我运行这些代码,则不会绘制运动轨迹。
请告诉我问题出在哪里。另外,星星必须以恒定的速度移动到点击的位置。 (不是传送)
以下是完整代码:
#include <stdlib.h>
#include <GL/glut.h>
float v1[3] = -35.0f, 22.5f, 0.0f ;
float v2[3] = -35.0f, -22.5f, 0.0f ;
float v3[3] = 0.0f, 42.5f, 0.0f ;
float v4[3] = 0.0f, -42.5f, 0.0f ;
float v5[3] = 35.0f, 22.5f, 0.0f ;
float v6[3] = 35.0f, -22.5f, 0.0f ;
float px, py;
float center_s[3] = 0.0f, 0.0f, 0.0f ;
float center_d[3] = px, py, 0.0f ;
static GLfloat spin = 0.0;
float x = 400.0f, y = 442.5f;
float color1[3] = 1.0f, 1.0f, 1.0f ;
float color2[3] = 1.0f, 1.0f, 1.0f ;
int mode = 1;
int rotate = 1;
void init(void);
void triangle_1(void);
void triangle_2(void);
void lines(void);
void display(void);
void spinDisplay_1(void);
void spinDisplay_2(void);
void reshape(int, int);
void changeColor(int);
void mouse(int, int, int, int);
////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(300, 300);
glutCreateWindow("6-Point Star");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
////////////////////////////////////////////////////////////////////
void init(void)
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
void triangle_1(void)
glColor3fv(color1);
glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v1);
glVertex3fv(v4);
glVertex3fv(v5);
glEnd();
void triangle_2(void)
glColor3fv(color2);
glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v2);
glVertex3fv(v3);
glVertex3fv(v6);
glEnd();
void lines(void)
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex3fv(center_s);
glLineWidth(1);
glBegin(GL_LINES);
glVertex3fv(center_s);
glVertex3fv(center_d);
void display(void)
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);
triangle_1();
triangle_2();
glPopMatrix();
glutSwapBuffers();
void spinDisplay_1(void)
spin = spin + 2.0;
if (spin > 360.0)
spin = spin - 360.0;
glutPostRedisplay();
void spinDisplay_2(void)
spin = spin - 2.0;
if (spin < 360.0)
spin = spin + 360.0;
glutPostRedisplay();
void reshape(int w, int h)
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
void changeColor(int n)
if (n == 1)
color1[0] = 0.0f, color1[1] = 0.0f, color1[2] = 1.0f;
color2[0] = 0.0f, color2[1] = 1.0f, color2[2] = 0.0f;
else if (n == 2)
color1[0] = 1.0f, color1[1] = 1.0f, color1[2] = 1.0f;
color2[0] = 1.0f, color2[1] = 1.0f, color2[2] = 1.0f;
void mouse(int button, int state, int mx, int my)
switch (button)
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
x = mx;
y = glutGet(GLUT_WINDOW_HEIGHT) - my;
px = x + 35.0;
py = y + 42.5;
glutIdleFunc(lines);
glutPostRedisplay();
break;
case GLUT_MIDDLE_BUTTON:
if (state == GLUT_DOWN)
if (mode == 1)
changeColor(mode);
mode = 2;
else if (mode == 2)
changeColor(mode);
mode = 1;
glutPostRedisplay();
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
if (rotate == 1)
glutIdleFunc(spinDisplay_1);
rotate = 2;
else if (rotate == 2)
glutIdleFunc(spinDisplay_2);
rotate = 1;
break;
default:
break;
【问题讨论】:
考虑到你最后三个问题,我建议你买一本关于 OpenGL 编程的好书。您添加到程序中的每一步似乎都有问题,这意味着最终您的整个应用程序是由一些 SO 成员编写的。 【参考方案1】:您缺少一些glEnd()
,除非您对center_s
和center_d
有其他计划,否则您不需要它们。因为x
和y
是center_s
,而px
和py
是center_d
。
所以首先在mouse()
中,只需将鼠标位置分配给px
和py
而不是x
和y
。
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
px = mx;
py = glutGet(GLUT_WINDOW_HEIGHT) - my;
接下来,您需要一种方法来获取增量时间。增量时间是自上一帧以来经过的时间。 为方便起见,我在display()
的顶部添加了以下代码。
int timeNow = glutGet(GLUT_ELAPSED_TIME);
float delta = (float)(timeNow - timeLastFrame) / 1000.0f;
timeLastFrame = timeNow;
记得在你的全局变量中声明int timeLastFrame = 0;
。
现在(仍在display()
)我们可以计算行进路径的方向。我们通过计算两点之间的差异来做到这一点。然后计算长度并将差异归一化。
float dx = px - x;
float dy = py - y;
float length = sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
现在你把它们放在一起。
if (length > 1.0f)
x += dx * speed * delta;
y += dy * speed * delta;
所以当length > 1.0
时,我们以float speed = 100.0f;
的速度向px
和py
移动(在你的全局变量中声明它)。
再次强调。是的,请从mouse()
中删除glutIdleFunc(lines)
。然后我们将其添加到display()
中。 display()
的完整扩展现在应该如下所示:
void display(void)
int timeNow = glutGet(GLUT_ELAPSED_TIME);
float delta = (float)(timeNow - timeLastFrame) / 1000.0f;
timeLastFrame = timeNow;
float dx = px - x;
float dy = py - y;
float length = sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
if (length > 1.0f)
x += dx * speed * delta;
y += dy * speed * delta;
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);
triangle_1();
triangle_2();
glPopMatrix();
lines();
glutSwapBuffers();
glutPostRedisplay();
记住glutPostRedisplay()
。如果不是,那么它不会重绘,因此不会动画。还记得#include <math.h>
为sqrt()
。
glClear()
之前的所有内容都可以移动到您的 glutIdleFunc()
回调中。
既然不需要center_s
和center_d
,那么lines()
可以归结为:
void lines(void)
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex2f(px, py);
glEnd();
glLineWidth(1);
glBegin(GL_LINES);
glVertex2f(x, y);
glVertex2f(px, py);
glEnd();
结果应该是这样的:
供日后参考。如果你不想手工做线性代数。然后你可以使用GLM之类的东西。
【讨论】:
感谢您的回答。但是你能解释更多关于dx /= length
和x += dx * speed * delta
的信息吗?
不客气! dx
是 px
和 x
之间的区别。所以这可能是0
1000
或任何东西。我们需要标准化这种差异,使其介于-1
和1
之间。基本上是以单位/法线向量的形式指向目标的方向。这意味着我们可以将此向量乘以x
,然后新位置将恰好与该位置相距x
。所以我们有我们的speed
,我们将它乘以delta
(自上一帧以来的时间),这样我们就知道要在帧上移动多少。
我想我必须学习线性代数......而且星星应该只在按下鼠标按钮时移动,但目前只要我运行程序它就会移动。所以我添加了一个全局变量trigger = 0;
并将if
条件length > 1.0f
编辑为length > 1.0f && trigger == 1
。最后我添加了trigger = 1
到GLUT_DOWN
左键案例的声明。但是从星星到屏幕左下角仍然画了一条红线。我是否必须更改 display()
函数中的某些内容?
是的,在lines()
绘制线条的地方,还要添加if (trigger == 1)
,这样你就只能在trigger
设置为1
时绘制它。以上是关于在OpenGL中绘制物体的轨迹的主要内容,如果未能解决你的问题,请参考以下文章