gluPerspective беше премахнат в OpenGL 3.1, има ли заместители?

Опитвам се да прочета някои уроци по OpenGL в мрежата. проблемът е, че намерих някои стари, които използват gluPerspective(). gluPerspective беше отхвърлен в OpenGL 3.0 и премахнат в 3.1.

Каква функция мога да използвам вместо това?

Използвам C++ с най-новия инсталиран FreeGlut.


person ufk    schedule 10.03.2010    source източник
comment
Знам, че е педантично, но gluPerspective никога не е бил част от OpenGL (оттук и префиксът glu). glFrustum беше и е отхвърлен.   -  person Bahbar    schedule 10.03.2010


Отговори (5)


Трябва да изчислите матрицата ръчно и след това да я предадете на OpenGL.

Изчисляване на матрицата

Този кодов фрагмент е базиран на документацията на gluPerspective.

 void BuildPerspProjMat(float *m, float fov, float aspect,
 float znear, float zfar)
 {
  float f = 1/tan(fov * PI_OVER_360);

  m[0]  = f/aspect;
  m[1]  = 0;
  m[2]  = 0;
  m[3]  = 0;

  m[4]  = 0;
  m[5]  = f;
  m[6]  = 0;
  m[7]  = 0;

  m[8]  = 0;
  m[9]  = 0;
  m[10] = (zfar + znear) / (znear - zfar);
  m[11] = -1;

  m[12] = 0;
  m[13] = 0;
  m[14] = 2*zfar*znear / (znear - zfar);
  m[15] = 0;
 }

Има C++ библиотека, наречена OpenGL Mathematics, която може да бъде полезна.

Зареждане на матрицата в OpenGL 3.1

Все още съм нов в API на OpenGL 3.1, но трябва да актуализирате матрица на графичния процесор и след това да я използвате във вашия вертекс шейдър, за да получите правилната перспектива. Следният код просто зарежда матрицата с помощта на glUniformMatrix4fv върху видеокартата.

{
  glUseProgram(shaderId);
  glUniformMatrix4fv(glGetUniformLocation(shaderId, "u_proj_matrix"),
                     1, GL_FALSE, theProjectionMatrix);
  RenderObject();
  glUseProgram(0);
}

Прост вертекс шейдър от произволен блог (намерен чрез препълване на стека).

attribute vec4      a_position;
attribute vec4      a_color;

varying vec4        v_color;

uniform mat4 u_proj_matrix;
uniform mat4 u_model_matrix;

void main() {
  mat4 mvp_matrix = u_proj_matrix * u_model_matrix;
  v_color = a_color;
  gl_Position = mvp_matrix * a_position;
}
person Dan    schedule 10.03.2010
comment
благодаря :) тази математическа библиотека opengl изобщо не изглежда лоша. - person ufk; 11.03.2010
comment
Тази функция не работи. Какво е xmax и ymax? Те се използват на втория ред и не са дефинирани - person gman; 26.07.2010
comment
Проследих източниците на статията обратно към оригинала, който е на френски: xgouchet.fr/blog/index.php/post/2009/07/27/. Той задава ymax = znear * tan(fov * PI_OVER_360); и получава чрез xmax = ymax * аспект. ymin = -ymax; xmin = ymin * аспект; - person Dan; 31.07.2010
comment
Работих по математиката за gluPerspective и glFrustum. Може да е по-спретнато да напишете ширина = xmax-xmin и височина = ymax-ymin; след което линията w = w/aspect няма да се изисква. - person koan; 18.11.2010
comment
Искам да добавя, че както се казва в коана, w = w/aspect ТРЯБВА да бъде премахнато от изчислението, както е сега, за да може матрицата да работи правилно. Самият аз използвах тази матрица и не можех да разбера защо аспектът е грешен, когато използвах нещо различно от 1 като аспект. Също така width = xymax - xmin трябва да бъде width = xmax - xmin, а height = xymax - ymin трябва да бъде height = ymax - ymin. - person DaedalusAlpha; 05.05.2011
comment
Трябва също да се отбележи, че fov е вертикалното fov. Лесно е случайно да посочите хоризонталния fov, тъй като обикновено това е, което игрите говорят от гледна точка. - person luke; 05.10.2011
comment
Може ли някой, който е тествал това, моля, редактирайте съответните промени, вместо да правите голям регистър на промените в коментарите. - person Rebs; 01.06.2014

Използвайте GLM.

glm::mat4 projection = glm::perspective(
  // FOV & aspect
  60.0f, 16.0f / 10.0f, 
  // Near and far planes
  0.001f, 1000f);

// If you're using the now deprecated matrix stacks
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(glm::value_ptr(projection));

// if you're using the new shader based pipelines
GLint projectionUniformLocation = ...;
glUniformMatrix4fv(projectionUniformLocation, 1, GL_FALSE, 
  glm::value_ptr(projection));

Забележете, ако сте дефинирали GLM_FORCE_RADIANS, тогава трябва да използвате радиани във функцията за перспектива, а не градуси...

glm::mat4 projection = glm::perspective(
  // FOV & aspect
  PI / 3.0f, 16.0f / 10.0f, 
  // Near and far planes
  0.001f, 1000f);
person Jherico    schedule 28.10.2013
comment
Имайте предвид, че започвайки от GLM 0.9.6.0, GLM_FORCE_RADIANS вече не е необходим, нито се поддържа, тъй като GLM сега работи само с радиани. - person Ruslan; 21.10.2017

Копирано от един от по-старите ми проекти:

// The following code is a fancy bit of math that is eqivilant to calling:
// gluPerspective( fieldOfView/2.0f, width/height , 0.1f, 255.0f )
// We do it this way simply to avoid requiring glu.h
GLfloat zNear = 0.1f;
GLfloat zFar = 255.0f;
GLfloat aspect = float(width)/float(height);
GLfloat fH = tan( float(fieldOfView / 360.0f * 3.14159f) ) * zNear;
GLfloat fW = fH * aspect;
glFrustum( -fW, fW, -fH, fH, zNear, zFar );
person Toji    schedule 10.03.2010
comment
Освен че glFrustum() също беше отхвърлен в 3.1. - person genpfault; 10.03.2010
comment
защо разделяте fieldOfView на 2.0f в gluPerspective. В спецификациите е посочено, че трябва да използвате пълния fov... - person meduz; 28.05.2013
comment
@genpfault Да, съвременният OpenGL изисква да работите с матрици за трансформация. - person bobobobo; 02.08.2013

Това е модифицирана версия на функцията на Дан с опростени изчисления от Неопределено поведение.

void buildPerspProjMat(GLfloat *m, GLfloat fov, GLfloat aspect,
GLfloat znear, GLfloat zfar){

  GLfloat h = tan(fov);
  GLfloat w = h / aspect;
  GLfloat depth = znear - zfar;
  GLfloat q = (zfar + znear) / depth;
  GLfloat qn = 2 * zfar * znear / depth;

  m[0]  = w;  m[1]  = 0;  m[2]  = 0;  m[3]  = 0;

  m[4]  = 0;  m[5]  = h;  m[6]  = 0;  m[7]  = 0;

  m[8]  = 0;  m[9]  = 0;  m[10] = q;  m[11] = -1;

  m[12] = 0;  m[13] = 0;  m[14] = qn;  m[15] = 0;
}
person shade4159    schedule 27.10.2013
comment
Мисля, че сте пропуснали малкото, където f (h във вашия код) = 1/tan(fovy/2), което е споменато във връзката, която предоставяте. - person Rebs; 01.06.2014
comment
Освен това тенът трябва да се извършва в радиани, а не в градуси. Сега резултатите съвпадат с този на Дан и моя собствен код. - person Rebs; 01.06.2014

Формулата за различни перспективни матрици е документирана в документацията на Direct3D.

Ето формулировката за D3DXMatrixPerspectiveFovRH, вдясно -ръчна перспективна проекционна матрица:

yScale = cot(fovY/2)
xScale = yScale / aspect ratio

xScale     0          0              0
0        yScale       0              0
0        0        zf/(zn-zf)        -1
0        0        zn*zf/(zn-zf)      0
person bobobobo    schedule 01.12.2012