Перспективная проекция, канонический объем просмотра - PullRequest
1 голос
/ 06 мая 2020
Vector3d nearC(0,0,0 -w);
Vector3d farC(0,0,0-x);
double width = y/2;
double height = z/2;
double angleOfHeight = atan(height/w);
double angleOfWidth = atan(width/w);
double adjustedHeight = tan(angleOfHeight) * x;
double adjustedWidth = tan(angleOfWidth) * x;

nearC[0] - width, nearC[1] - height, nearC[2]
nearC[0] - width, nearC[1] + height, nearC[2]
nearC[0] + width, nearC[1] + height, nearC[2]
nearC[0] + width, nearC[1] - height, nearC[2]
farC[0] - adjustedWidth, farC[1] - adjustedHeight, farC[2]
farC[0] - adjustedWidth, farC[1] + adjustedHeight, farC[2]
farC[0] + adjustedWidth, farC[1] + adjustedHeight, farC[2]
farC[0] + adjustedWidth, farC[1] - adjustedHeight, farC[2]

Выше моя усеченная пирамида в координатах обзора. Матрица просмотра:

 0   0  -1   0
 0   1   0  -1
 1   0   0 -10
 0   0   0   1

Все правильно, у нас есть лист.

Да хоть убей я не могу понять, как получить эту усеченную пирамиду в каноническом объеме просмотра. Я просмотрел все перспективные проекции, которые смог найти. Текущий следующий:

        s,        0,                      0,                     0,
        0,        s,                      0,                     0,
        0,        0,             -(f+ne)/(f-ne),            2*f*ne/(f-ne),
        0,        0,                      1,                     0;

double s = 1 / tan (angleOfView * 0.5 * M_PI / 180);

Мне не хватает шага или чего-то, верно? Или несколько шагов?

Извини за то, что сейчас звучит так безнадежно, какое-то время крутит колеса над этим.

Любая помощь приветствуется.

1 Ответ

2 голосов
/ 06 мая 2020

Не начинать с перспективной проекции. Обычный способ в старой GL - использовать gluPerspective.

, для этого нам нужно znear,zfar,FOV и соотношение сторон обзора. Для получения дополнительной информации см .:

  • Расчет матрицы перспективной проекции в соответствии с плоскостью обзора

    Я привык использовать FOVx (угол обзора по оси x). Чтобы вычислить это, вам нужно посмотреть на пирамиду сверху, глядя на плоскость xz (в пространстве камеры):

    frustrum XY plane

    так:

    tan(FOVx/2) = znear_width / 2*focal_length
    FOVx = 2*atan(znear_width / 2*focal_length)
    

    фокусное расстояние может быть вычислено путем вычисления пересечения линий краев пирамиды. Или используя подобие треугольника. Второе проще написать:

    zfar_width/2*(|zfar-znear|+focal_length) = znear_width/2*(focal_length)
    zfar_width/(|zfar-znear|+focal_length) = znear_width/(focal_length)
    focal_length = (|zfar-znear|+focal_length)*znear_width/zfar_width
    focal_length - focal_length*znear_width/zfar_width = |zfar-znear|*znear_width/zfar_width 
    focal_length*(1-(znear_width/zfar_width)) = |zfar-znear|*znear_width/zfar_width 
    focal_length = (|zfar-znear|*znear_width/zfar_width) / (1-(znear_width/zfar_width))
    

    и это все, что нам нужно, так что:

    focal_length = (|zfar-znear|*znear_width/zfar_width) / (1-(znear_width/zfar_width))
    FOVx = 2*atan(znear_width / 2*focal_length)        
    FOVx*=180.0/M_PI; // convert to degrees
    aspect=znear_width/znear_height;
    gluPerspective(FOVx/aspect,aspect,znear,zfar);
    

    просто имейте в виду, что |zfar-znear| - это перпендикулярное расстояние между плоскостями !!! Поэтому, если у вас нет выровненных по оси, вам нужно вычислить это, используя точечное произведение и нормальное ...

...