gpt4 book ai didi

c - 恒定的游戏速度与GLUT在OpenGL中与可变FPS无关吗?

转载 作者:行者123 更新时间:2023-12-03 01:15:38 26 4
gpt4 key购买 nike

我一直在阅读有关不同游戏循环解决方案的Koen Witters detailed article,但是我在使用GLUT实现最后一个方面遇到了一些问题,这是推荐的解决方案。

在阅读过其他一些关于如何实现恒定游戏速度的文章,教程和代码后,我认为我目前实现的(我将在下面的代码中发布)就是Koen Witters所说的依赖于可变FPS的游戏速度。 ,他文章的第二篇。

首先,根据我的搜索经验,可能会有一些人对此有帮助的知识,但是他们不知道GLUT是什么,因此我将尽力解释(随时纠正我)与之相关的功能我的OpenGL工具包的问题。如果您知道什么是GLUT以及如何使用它,请跳过本节。

GLUT工具包:


GLUT是OpenGL工具包,可帮助完成OpenGL中的常见任务。
glutDisplayFunc(renderScene)带有指向renderScene()函数回调的指针,该函数负责呈现所有内容。 renderScene()函数将仅在回调注册后被调用一次。
glutTimerFunc(TIMER_MILLISECONDS, processAnimationTimer, 0)在调用回调processAnimationTimer()之前花费了毫秒数。最后一个参数只是传递给计时器回调的值。 processAnimationTimer()不会被每个TIMER_MILLISECONDS调用,而只会被调用一次。
glutPostRedisplay()函数请求GLUT渲染新帧,因此每次我们更改场景中的内容时都需要调用此帧。
glutIdleFunc(renderScene)可以用于注册到renderScene()的回调(这不会使glutDisplayFunc()无关紧要),但应避免使用此函数,因为在未接收到事件时会连续调用空闲回调,从而增加了CPU负载。
glutGet(GLUT_ELAPSED_TIME)函数返回自调用glutInit(或首次调用glutGet(GLUT_ELAPSED_TIME))以来的毫秒数。那就是我们使用GLUT的计时器。我知道高分辨率计时器还有更好的选择,但是现在让我们继续使用它。


我认为这是有关GLUT如何渲染帧的足够信息,因此不知道它的人也可以提出这个问题,以尝试帮助他们,如果他们喜欢它。

当前实施:

现在,我不确定我是否已经正确实施了Koen提出的第二种解决方案,即依赖可变FPS的游戏速度。与此相关的代码如下所示:

#define TICKS_PER_SECOND 30
#define MOVEMENT_SPEED 2.0f

const int TIMER_MILLISECONDS = 1000 / TICKS_PER_SECOND;

int previousTime;
int currentTime;
int elapsedTime;

void renderScene(void) {
(...)

// Setup the camera position and looking point
SceneCamera.LookAt();

// Do all drawing below...

(...)
}

void processAnimationTimer(int value) {
// setups the timer to be called again
glutTimerFunc(TIMER_MILLISECONDS, processAnimationTimer, 0);

// Get the time when the previous frame was rendered
previousTime = currentTime;

// Get the current time (in milliseconds) and calculate the elapsed time
currentTime = glutGet(GLUT_ELAPSED_TIME);
elapsedTime = currentTime - previousTime;

/* Multiply the camera direction vector by constant speed then by the
elapsed time (in seconds) and then move the camera */
SceneCamera.Move(cameraDirection * MOVEMENT_SPEED * (elapsedTime / 1000.0f));

// Requests to render a new frame (this will call my renderScene() once)
glutPostRedisplay();
}

void main(int argc, char **argv) {
glutInit(&argc, argv);

(...)

glutDisplayFunc(renderScene);

(...)

// Setup the timer to be called one first time
glutTimerFunc(TIMER_MILLISECONDS, processAnimationTimer, 0);
// Read the current time since glutInit was called
currentTime = glutGet(GLUT_ELAPSED_TIME);

glutMainLoop();
}


此实现不正确。从某种意义上说,它可以帮助游戏速度始终取决于FPS。因此,无论高帧率还是低帧率,从点A到点B都需要花费相同的时间。但是,我相信我用这种方法限制了游戏的帧率。 [编辑:仅在调用时间回调时才渲染每个帧,这意味着帧速率大约为每秒 TICKS_PER_SECOND个帧。这感觉不对,您不应该限制强大的硬件,这是错误的。据我了解,我仍然需要计算 elapsedTime。只是因为我要告诉GLUT每个 TIMER_MILLISECONDS调用计时器回调,但这并不意味着它将始终按时执行。]

我不确定如何解决这个问题,说实话,我不知道GLUT中的游戏循环是什么,你知道Koen文章中的 while( game_is_running )循环。 [编辑:据我了解,GLUT是事件驱动的,当我调用 glutMainLoop()(永不返回)时,游戏循环便开始了,是吗?]

我以为我可以向 glutIdleFunc()注册一个空闲的回调并将其用作 glutTimerFunc()的替换,仅在必要时渲染(而不是像往常一样),但是当我使用空回调(例如 void gameLoop() {})对其进行测试时基本上什么也没做,只有黑屏,CPU飙升到25%并保持在那里,直到我杀死了游戏,然后它恢复了正常。所以我不认为这是可以遵循的道路。

因此,使用 glutTimerFunc()绝对不是一种执行所有动作/动画的好方法,因为我将游戏限制为恒定的FPS,而不是炫酷。还是我使用错了,而我的实现不正确?

可变FPS时,我如何才能保持恒定的游戏速度?更确切地说,我该如何使用GLUT正确实现Koen的恒定游戏速度和最大FPS解决方案(他的文章中的第四个解决方案)?也许用GLUT根本不可能吗?如果没有,我有什么选择?使用GLUT解决此问题(恒定游戏速度)的最佳方法是什么?

[编辑]另一种方法:

我一直在尝试,这是我现在能够实现的目标。现在,不是在计时功能上计算经过的时间(这会限制游戏的帧速率),而是在 renderScene()中进行计算。每当场景发生变化时,我都会调用 glutPostRedisplay()(即:摄像机移动,某些对象动画等),这将调用 renderScene()。例如,我可以在此功能中使用经过的时间来移动相机。

我的代码现在变成了:

int previousTime;
int currentTime;
int elapsedTime;

void renderScene(void) {
(...)

// Setup the camera position and looking point
SceneCamera.LookAt();

// Do all drawing below...

(...)
}

void renderScene(void) {
(...)

// Get the time when the previous frame was rendered
previousTime = currentTime;

// Get the current time (in milliseconds) and calculate the elapsed time
currentTime = glutGet(GLUT_ELAPSED_TIME);
elapsedTime = currentTime - previousTime;

/* Multiply the camera direction vector by constant speed then by the
elapsed time (in seconds) and then move the camera */
SceneCamera.Move(cameraDirection * MOVEMENT_SPEED * (elapsedTime / 1000.0f));

// Setup the camera position and looking point
SceneCamera.LookAt();

// All drawing code goes inside this function
drawCompleteScene();

glutSwapBuffers();

/* Redraw the frame ONLY if the user is moving the camera
(similar code will be needed to redraw the frame for other events) */
if(!IsTupleEmpty(cameraDirection)) {
glutPostRedisplay();
}
}

void main(int argc, char **argv) {
glutInit(&argc, argv);

(...)

glutDisplayFunc(renderScene);

(...)

currentTime = glutGet(GLUT_ELAPSED_TIME);

glutMainLoop();
}


结论,它正在起作用,或者看起来如此。如果我不移动相机,则CPU使用率很低,没有渲染任何内容(出于测试目的,我只有一个扩展为4000.0f的网格,而zFar设置为1000.0f)。当我开始移动相机时,场景开始重绘。如果我一直按移动键,则CPU使用率会增加;这是正常现象。当我停止移动时,它回落。

除非我缺少任何东西,否则目前看来是一个不错的方法。我确实在iDevGames上找到了 this interesting article,并且此实现可能受到该文章中所述问题的影响。您对此有何看法?

请注意,我这样做只是出于娱乐目的,我无意创建一些要分发的游戏或类似的东西,至少在不久的将来不会。如果这样做的话,我可能会选择除GLUT之外的其他东西。但是,由于我使用的是GLUT,而不是iDevGames上描述的问题,因此您认为此最新实现对GLUT足够了吗?我现在能想到的唯一真正的问题是,每次场景变化时,我都需要继续调用 glutPostRedisplay()并不断调用它,直到没有新内容可以重绘为止。我认为,为了更好的原因,在代码中添加了一些复杂性。

你怎么看?

最佳答案

过剩被设计为游戏循环。当您调用glutMainLoop()时,它将执行一个“ for循环”,除了exit()信号外,没有终止条件。您可以像现在一样执行程序,但是需要一些小的更改。首先,如果您想知道什么是FPS,则应将该跟踪放入renderScene()函数中,而不要放在update函数中。自然地,您的更新函数将按照计时器指定的速度被调用,并且您将elapsedTime视为帧之间时间的度量。通常,这是正确的,因为您调用glutPostRedisplay的速度很慢,并且在不需要时glut不会尝试更新屏幕(如果场景未更改,则无需重绘)。但是,有时还会调用renderScene。例如,如果您在窗口上拖动某些东西。如果这样做的话,您会看到更高的FPS(如果您在渲染功能中正确跟踪了FPS)。

关于c - 恒定的游戏速度与GLUT在OpenGL中与可变FPS无关吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5357119/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com