2013-07-12 2 views
0

Я преподаю, как использовать OpenGL для создания графики, и у меня есть базовый спиральный скрипт + вращение. Вращение Y-оси автоматически основано на функции таймера, но я заметил, что когда я перемещаю мышь внутри окна, он, кажется, вращается быстрее, чем предполагалось. Может кто-нибудь, пожалуйста, просмотрите мой сценарий и скажите, что вызывает ускорение функции таймера?Движение мыши ускоряет выполнение кода?

#include <Windows.h> 
#include <glut.h> 
#include <stdio.h> 
#include <math.h> 

// Change viewing volume and viewport. Called when window is resized 
void ChangeSize(GLsizei w, GLsizei h) 
{ 
    GLfloat nRange = 100.0f; 

    //Prevent a divide by zero 
    if(h == 0) 
     h = 1; 

    // Set Viewport to window dimensions 
    glViewport(0, 0, w, h); 

    // Reset projection matrix stack 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 

    // Establish clipping volume (left, right, buttom, top, near, far) 
    if (w<= h) 
     glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange); 
    else 
     glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange); 

//Reset Model view matrix stack 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
} 

//Define a constant for pi 
#define GL_PI 3.1415f 

// This function does all the initialization 
void SetupRC() 
{ 
    // Black background 
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 

    // Set drawing color to green 
    glColor3f(0.0f, 1.0f, 0.0f); 
} 


// Test declaration of rotation angle 
GLfloat xRot = 0; 
GLfloat yRot = 0; 

// Modifiable variables for the eccentricity 
    GLfloat xMod = 50.0f; 
    GLfloat yMod = 50.0f; 

// Called to draw scene 
void RenderScene(void) 
{ 
    GLfloat x,y,z,angle; // Storage for coordinates and angles 
    GLfloat sizes[2]; // Store supported point size range 
    GLfloat step; // Store point size increments 
    GLfloat curSize; //Store current point size 
    // Get supported point size range and step size 
    glGetFloatv(GL_POINT_SIZE_RANGE, sizes); 
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &step); 

//Set the initial point size 
curSize = sizes[0]; 

// Clear the window with current clearing color 
glClear(GL_COLOR_BUFFER_BIT); 

// Save matrix state and do the rotation 
glPushMatrix(); 
glRotatef(xRot, 1.0f, 0.0f, 0.0f); 
glRotatef(yRot, 0.0f, 1.0f, 0.0f); 

// specify point size before primitive is specified 
glPointSize(curSize); 

//Call only once for remaining points 
glBegin(GL_LINE_STRIP); 

//Set beginning z coordinate 
z = -50.0f; 

//Loop around in a circle three times 
for (angle = 0.0f; angle <= (2.0f*GL_PI)*3.0f; angle += 0.1f) 
{ 
    // Calculate x and y values on the circle (the major and minor axis) 
    x = xMod*sin(angle); 
    y = yMod*cos(angle); 
    // Specify the point and move the z value up a little 
    glVertex3f(x, y, z); 
    z += 0.5f; 
} 

// Done drawing points 
glEnd(); 




// Restore transformations 
glPopMatrix(); 

//Flush drawing commands 
glFlush(); 
} 

// Modifier Code 
void CircleController (int key, int x, int y) 
    { 
switch (key) 
{  
    case 27 :  break; 

    case 100 : 

       (yRot -= 5.0f); ; break; 

    case 102 : 

       (yRot += 5.0f); ; break; 

    case 101 : 

       (xRot -= 5.0f); ; break; 

    case 103 :  

       (xRot += 5.0f); ; break; 
glutDisplayFunc(RenderScene); 
} 

} 

void MouseHandler (int button, int state, int x, int y) 
{ 
    // Holder variable assigned to overcome printf limitation and prevent double- printing due to MouseUp function call 
    GLfloat Holder = xMod; 
    // Increases size, and decreases timer speed by increasing the amount of time  needed. 
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 
     { 
       xMod+= 5.0f; 

    } 

     // Decreases size, and increases timer speed by decreasing the amount of  time needed. 
    if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) 
     { 
      xMod-= 5.0f ; 

    } 

    if (Holder != xMod) 
     printf("%d \n", Holder); 

} 

void TimerFunction(int value) 
{ 
    //Call the arrow key function 
    glutSpecialFunc(CircleController); 

    //Call the Mouseclick Modifier function 
    glutMouseFunc(MouseHandler); 

    if (xRot < 360) 
    (xRot += 1.0f); 
    else 
    (xRot = 0.0f); 


    // Redraw the scene with new coordinates 
    glutPostRedisplay(); 
    glutTimerFunc(1.6666f, TimerFunction, 1); 

} 



void main(void) 
{ 
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 
    glutCreateWindow("Drawing Lines"); 
    glutDisplayFunc(RenderScene); 
    glutReshapeFunc(ChangeSize); 
    glutTimerFunc(1.6666f, TimerFunction, 1); 
    SetupRC(); 

    glutMainLoop(); 
} 
+1

У меня была аналогичная проблема, когда я работал в OpenGL несколько лет назад. Я никогда не нашел для этого решения, но я подумал, что было бы хорошо знать, что, по крайней мере, вы не одиноки! Моя личная теория всегда заключалась в том, что она имела какое-то отношение к фокусу окна, и какой программе дается больше процессорного времени, но это просто чистая спекуляция. –

+1

Почему вы передаете '1.6666f' функции, ожидающей' unsigned int'? –

+0

Я заметил разницу в скорости выполнения в сравнении с тем, сколько ram/сколько моего процессора использовалось. Если бы у меня был фотошоп или Firefox с открытыми Facebook, мой код, казалось, быстро вышел и быстро выполнил. Нечетные вещи произойдут, если я изменю настройки батареи на моем ноутбуке. OpenGL делает странные вещи. Кроме того, я думаю, что я неверно истолковал параметры из книги. Ухмыляясь, я думаю, вы, возможно, нашли проблему. Я изменил его на целое число, и, похоже, сейчас он работает отлично, спасибо вам большое! Можете ли вы объяснить ошибочное поведение? Или вы просто знаете, что вызвало это? – Kain

ответ

0

Eric Palace дал мне старт

Моя личная теория всегда было то, что это было что-то делать с окном фокуса и какая программа уделять больше процессорного времени, но это только чистая спекуляция.

Это имеет смысл для меня. Но подождите, разве вы не красите только таймер? Разве это не мешало бы увеличить время процессора от изменения скорости движения? Да, да. Вроде.

glutTimerFunc(1.6666f, TimerFunction, 1); 

ДИЗКНО для glutTimerFunc сказать, что первый параметр является unsigned int, представляющим таймера в миллисекундах. Таким образом, вы говорите глупость, называете эту функцию каждые 1 миллисекунду. (Приблизительно 1000FPS). И так как для выполнения требуется более одного миллисекунды, вы эффективно говорите, что «повторяйте эту функцию снова и снова так быстро, как вы можете». Что он делает. И поэтому дополнительное время процессора равно, что делает разницу.

Чтобы избежать situtations, как это (помимо коррекции параметра 1.6666f), это, как правило, предлагается

  • обновления «мир» в отдельных функциях от живописи экрана. На самом деле, я бы предположил, что это общепринято для того, чтобы иметь две или более функции обновления мира. Один для материала, который нуждается в обновлении с помощью краски: стрелки и символы запуска, один для материала, который изменяется только один раз или около того: решения mana regen и npc и один для очень медленного материала: respawns.
  • Во время «обновления» проверьте, сколько времени прошло с момента последнего обновления (максимум на полсекунды или около того), и сделайте обновление мира так много. Затем, если обновления будут выполняться в два раза чаще или вдвое чаще, по какой-либо причине, игра не будет ускоряться или замедляться, вместо этого вы просто просто больше/меньше кадров.

Вот что такое обновление может выглядеть

radians xrot = 0; //use a units class 
radians rot_per_second = .01; 

void updateFrame(double time_passed) { 
    assert(time_passed>=0 && time_passed <= 1.0); 
    radians rotate_thistime = rot_per_second * time_passed; 
    xrot += rotate_thistime; 
} 

void do_updates() { 
    static clock_t lastupdatetime = clock()-1; //use openGL functions instead of C 
    clock_t thisupdatetime = clock(); 
    double seconds = double(thisupdatetime-lastupdatetime)/CLOCKS_PER_SEC; 
    if (seconds > 0.5) //if something happened and haven't update in a long time 
     seconds = 0.5; //pretend only half a second passed. 
    //this can happen if 
    // computer is overloaded 
    // computer hibernates 
    // the process is debugged 
    // the clock changes 
    if (seconds <= 0.0) //computer is REALLY fast or clock changed 
     return; //skip this update, we'll do it when we have sane numbers 

    updateFrame(seconds); 
    lastupdatetime = thisupdatetime; 
} 
+0

Да, причина, по которой я специально выбрал этот номер, должен был иметь программный процесс на 60 "FPS" (действительно рендер в секунду). Сроки не слишком важны, я просто хотел, чтобы она текла. – Kain

+0

@Kain: Вы просчитались. ваш код говорит об обновлении на 600 FPS, но из-за округления он пытается сделать 1000 FPS. –

+0

Кроме того, стоит отметить, что большие фильмы с блокбастерами _still_ застрелили всего 24 FPS. Игровые консоли, такие как XBox и PS3, обычно работают около 30 FPS. Очень немногие компьютерные игры действительно работают на 60FPS. Поэтому, если вы считаете, что ваши видеоигры выглядят хорошо, вы теперь знаете, что 24-30FPS отлично подходит для того, что вы делаете. –

Смежные вопросы