как рассчитать параметры glFrustum?

#c #opengl #graphics #glfrustum

Вопрос:

У меня есть этот код:

 /*
 * This is a simple program that computes FPS
 * by means of a circular buffer
 */
#include <GL/glut.h>
//#include <numeric>
#include <unistd.h>
#include <time.h>
#include <stdio.h>

// Number of elements in the circular buffer
#define NELS    10

// Number of lines
#define NLINES  10000

// circular buffer used to compute frame rate
float circularBuffer[NELS];
int firstInd = 0, nEls = 0;

// function to get the number of elapsed ticks
uint32_t getTick()
{
    struct timespec ts;
    unsigned theTick = 0U;
    clock_gettime( CLOCK_REALTIME, amp;ts );
    theTick  = ts.tv_nsec / 1000000;
    theTick  = ts.tv_sec * 1000;
    return theTick;
}

// Function to compute real modulus and NOT remained as % does
inline int modulo(int a, int b) {
    const int result = a % b;
    return result >= 0 ? result : result   b;
}

// Compute sum of the elements in the circular buffer
float sumCircularBuffer()
{
    int ind;
    float sum = 0;

    if (nEls > 0) {
        for (ind=1; ind<=nEls; ind  ) {
            sum = sum   circularBuffer[modulo(firstInd-ind, NELS)];
        }
    }

    return sum;
}

// accumulate buffer and update window title
void computeAndShowFrameRate(void)
{
    static float lastTime = 0.0f;
    static unsigned int frameCount = 0;
    char windowTitle[100];
    float sumFPS;

    float currentTime = (float)getTick() * 0.001f;
    // Initialize lastTime to the current time
    if (lastTime == 0) {
        lastTime = currentTime;
    }

    // increase frame count
    frameCount  ;
    if (currentTime - lastTime > 1.0f) {
        // insert the current fps in the circular buffer
        circularBuffer[firstInd] = ((float)frameCount) / (currentTime - lastTime);

        // update variable lastTime
        lastTime = currentTime;

        //circularBuffer[firstInd] = (float)frameCount;
        firstInd = ((firstInd 1)%NELS);
        if (nEls < NELS) {
            nEls  ;
        }
        frameCount = 0;

        // sum elements in circular buffer
        sumFPS = sumCircularBuffer();
        snprintf(windowTitle, 100, "FPS = %6.2f", sumFPS/nEls);
        // update window title
        glutSetWindowTitle(windowTitle);
    }
}

// display function
void display(void)
{
    int currLineInd;

    // get current frame rate
    computeAndShowFrameRate();

    // clear buffer
    glClear (GL_COLOR_BUFFER_BIT);

    for (currLineInd = 0; currLineInd<NLINES; currLineInd  ) {
        // draw line
        glBegin(GL_LINES);
        // random color
        glColor3f((float)rand()/RAND_MAX, (float)rand()/RAND_MAX, (float)rand()/RAND_MAX);
        // random first point
        glVertex2f((float)rand()/RAND_MAX, (float)rand()/RAND_MAX);
        // random color
        glColor3f((float)rand()/RAND_MAX, (float)rand()/RAND_MAX, (float)rand()/RAND_MAX);
        // random second point
        glVertex2f((float)rand()/RAND_MAX, (float)rand()/RAND_MAX);
        glEnd();
    }

    glFinish();
    glutPostRedisplay();
}

// initialization function
void init (void)
{
    // Use current time as seed for random generator
    srand(time(0));

    // select clearing color
    glClearColor (0.0, 0.0, 0.0, 0.0);

    // Orthographic projection
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

// Window size and mode
int main(int argc, char** argv)
{
    // pass potential input arguments to glutInit
    glutInit(amp;argc, argv);

    // set display mode
    // GLUT_SINGLE = single buffer window
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

    glutInitWindowSize (400, 400);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("OpenGL Window");

    // Call initialization routinesx
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}
 

Я должен заменить функцию glOrtho на glFrustum и получить тот же результат.

Я прочитал руководство opengl по хроносу и понял различия между glOrtho и glFrustum, но я не могу понять, как рассчитать параметры.

Как рассчитать параметры для передачи в функцию glFrustum?

Комментарии:

1. Я думаю, что большинство людей этого не делают, они используют gluPerspective.

2. @user253751 Нет, gluPerspecctive glFrustum в наши дни никто не использует или, потому что конвейер с фиксированной функцией устарел на десятилетия.

3. @Rabbid76 ну да, но когда они используют конвейер с фиксированной функцией, они используют gluPerspective. Или glm::перспектива для тех из нас, кто этим не пользуется.

4. @user253751 Ты прав. Для симметричной проекции более распространенным способом является glm::perspective .

Ответ №1:

glFrustum() требуется 6 параметров для указания 6 плоскостей отсечения: левая, правая, нижняя, верхняя, ближняя и дальняя плоскости. Визуальное представление было бы таким: введите описание изображения здесь

Значения, которые будут получены, зависят от вашей реализации и масштаба моделей, с которыми вы работаете. Как упоминалось выше, если проецируемая геометрия находится перед ближней плоскостью или за дальней плоскостью, она будет обрезана, поэтому ее не будет видно.

Чтобы решить эту проблему, вам нужно либо пересчитать параметры glFrustum() функции(плохая идея), либо переместить камеру/сцену вдоль оси z.

Рекомендации:

  1. http://www.songho.ca/opengl/gl_transform.html
  2. https://learnopengl.com/Getting-started/Coordinate-Systems

Комментарии:

1. Вы сами нарисовали этот образ?

2. Нет, именно поэтому я добавил «ссылки».

Ответ №2:

При перспективной проекции расстояние до ближней и дальней плоскости должно быть больше 0,

 0 < near < far
 

потому что вы хотите определить усеченное сечение просмотра:

Если расстояние до ближней плоскости меньше 0, результат не определен (обычно инструкция вообще не действует).

Видеть glFrustum :

 void glFrustum( GLdouble left,
    GLdouble right,
    GLdouble bottom,
    GLdouble top,
    GLdouble nearVal,
    GLdouble farVal);
 

Расстояния left , right , bottom и top -это расстояния от центра обзора до боковых граней усеченного конуса на ближней плоскости. near и far укажите расстояния до ближней и дальней плоскости усеченного конуса.

Геометрия должна находиться между ближней и дальней плоскостями, иначе она обрезается. Поэтому вы должны переместить сдвиг вдоль оси z в отрицательном направлении (в отрицательном направлении, потому что ось z пространства просмотра указывает вне поля зрения).:

 // initialization function
void init (void)
{
    // [...]

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-0.1, 0.1, -0.1, 0.1, 0.1, 50.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -5.0f);
}