c++ - 在 OpenGL 中绘制物体的轨迹

标签 c++ c opengl

我想制作当我点击屏幕上的任何位置时对象移动时绘制轨迹的代码。

我将初始中心点设置为起点。我想将单击鼠标按钮的另一个点(目标点)设置为变量,但我不知道该怎么做。

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 };

这是对象的初始位置。 (带有 2 个三角形的 6 点星)

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_scenter_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;
    }
}

最佳答案

你错过了一些 glEnd()除非你对 center_s 有其他计划和 center_d那么你不需要它们。作为xycenter_s , 而 pxpycenter_d .

所以首先在mouse()只需将鼠标位置分配给 pxpy而不是 xy .

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然后我们走向pxpyfloat speed = 100.0f; 的速度(也在你的全局变量中声明它)。

再强调一下。是的,请删除 glutIdleFunc(lines)来自 mouse() .然后我们把它添加到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_scenter_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 的东西.

关于c++ - 在 OpenGL 中绘制物体的轨迹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43164540/

相关文章:

c++ - 如何在Objective-C/C/C++中进行字符和字节位置的转换

c++ - C/C++ 中的可移植目录/文件监视库

c++ - linux动态链接库注入(inject)

c++ - C++ 中自定义类的 HashMap 中的默认值

c - 从 C 中的不同文件访问结构

c - 如何检查结构体中的变量是否未在 C 中使用?

c++ - 如何使用 GLEW、OpenGL 或 SDL2 以椭圆运动围绕另一个圆旋转?

opengl - 为什么要绑定(bind)OpenGL缓冲区对象?

c++ - 是否可以将 C++ 接口(interface)与 Objective-C 一起使用?

c++ - 使用 GL_DRAW_FRAMEBUFFER 目标时,glBindFramebuffer 会导致 "invalid operation"GL 错误