目前,我有一个非常简单的应用程序,它基本上是我要在继续进行之前正确整理的核心循环。

我正在按照gaffer的要求修改时间步文章,但是我必须做错了,因为渲染四边形围绕所有三个轴旋转时,我已经放下了帧。基本上达到了代码的if(frame_time > 0.025)..行,这使我相信自己在做错误的事情。更糟糕的是,我仅渲染到320x480视口,仅清除背景色。

这是核心功能。我有一些变数

double delta_time = 1.0f/60.0f;
double frame_time;
double start_time;
double current_time;
double accum;
static int ce_run_game() {
while (game_running > 0) {
    current_time = SDL_GetTicks();
    frame_time = (current_time - start_time) * 0.001f; //convert from 250ms to 0.025

    printf("ft: %f\n",frame_time);

    if (frame_time >= 0.025){
        frame_time = 0.025;
        printf("slowdown\n");
    }

    start_time = current_time;


    while (SDL_PollEvent(&event)) {
        ce_handle_events(&event);
        }
        if (event.type == SDL_QUIT) {
            ce_quit();
        }
    }

    accum += frame_time;
    while (accum >= delta_time) {
        accum -= delta_time;
        ce_fixed_update();
        ce_fixed_render();
    }

    double alpha = accum / delta_time;
    // state = current_state * alpha + prev_state * (1.0 - alpha);
    ce_var_update(alpha);
    ce_var_render(alpha);
}

    return -1;
}


通过这个简单的循环,我似乎正在丢帧。与代码相关的另一部分是运动代码。尽管这没什么了不起的,但它并不会导致太多的减速。

通常,帧时间打印语句徘徊在0.016-0.017左右

但有时甚至会提高很多,甚至达到0.85甚至更高。在上述if(frame_time > 0.025)中添加东西似乎会停留在0.16 0.17左右,但是我不确定为什么帧时间会突然增加并且它们变得不受控制,尤其是因为我只在屏幕上移动一件事。

运动代码:

static void handle_event(SDL_Event* e) {
    switch (e->type) {
        case SDL_KEYUP:
            left = right = up = down = 0;
            break;
        case SDL_KEYDOWN:
            switch (e->key.keysym.sym) {
                case SDLK_AC_BACK:
                case SDLK_ESCAPE:
                    ce_quit();
                    break;
                case SDLK_LEFT:
                    left = 1;
                    break;
                case SDLK_RIGHT:
                    right = 1;
                    break;
                case SDLK_UP:
                    up = 1;
                    break;
                case SDLK_DOWN:
                    down = 1;
                    break;
            }
    }
}


static void variable_render(double alpha) {
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(ce_get_default_shader()->shader_program);
    glBindVertexArray(vao);

    vvv = vec3_new(1, 1, 1);
    angle += 0.0015f * alpha;
    if (angle >= 360.0) angle = 0.0f;
    mat4_rotate(model_mat, model_mat, angle, vvv);

    ce_get_view_matrices(&vview_mat, &pproj_mat, &mmvp_mat);

    mat4_multi(&mmvp_mat, &vview_mat, model_mat);
    mat4_multi(&mmvp_mat, &pproj_mat, &mmvp_mat);
    glUniformMatrix4fv(mvp_matrix_loc, 1, GL_FALSE, mat4_get_data(&mmvp_mat));

    glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, mat4_get_data(model_mat));
    glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, mat4_get_data(&vview_mat));
    glUniformMatrix4fv(proj_matrix_loc, 1, GL_FALSE, mat4_get_data(&pproj_mat));

    glDrawElements(GL_TRIANGLES, quad->vertex_count, GL_UNSIGNED_SHORT, 0);
    glBindVertexArray(0);

}

最佳答案

我必须在这里回答我自己的问题,但似乎手头有两个问题。

其中之一是由于vsync而导致此速度下降,关闭vsync完全摆脱了速度下降,这实际上不是我的逻辑更新速度下降,而是渲染速度下降。由于我使用的是固定步骤,因此这不是一个大问题。

另一个问题是SDL_GetTicks()不太准确。我用clock_gettime(realtimeclock ...)重新编写了计时功能,它的编号更加一致。

例如,SDL_GetTicks每次更新将返回240ms至267ms的任意值,而clock_gettime在250ms更新时保持一致。

我使用的是SDL_SetDelay(0.25 * 1000),并且clock_gettime正确,SDL缺少一点。

它不像SDL那样具有跨平台的功能,但是有一个针对Windows和Mac的高性能计数器,可以轻松实现。

这是我用于计时btw的代码。

#define _POSIX_C_SOURCE 199309L
#include "headers/timer_utils.h"

void tu_set_current_time(timer* time) { clock_gettime(CLOCK_REALTIME, time); }

void tu_copy_current_time(timer* to, timer* from) {
    to->tv_sec = from->tv_sec;
    to->tv_nsec = from->tv_nsec;
}

double tu_get_time_diff(timer* start, timer* finish) {
    return (finish->tv_sec - start->tv_sec) +
           (finish->tv_nsec - start->tv_nsec) * 0.000000001;// / 1E9;
}

关于c - gaffer固定时间步下降帧,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33981565/

10-11 08:56