2013-06-18 2 views
1

В эти дни я читаю книгу Learning Modern 3D Graphics Programming Джейсона Л. МакКессона. В основном это книга об OpenGL 3.3, и теперь я нахожусь в chapter 4, то есть о орфографическом и перспективном виде.Как установить конкретную точку зрения с использованием перспективного вида с шейдерами

В конце главы, в разделе "Further Study", он предлагает попробовать несколько вещей, таких как внедрение переменной глазной точки (он использовал в начале (0, 0, 0) в пространстве камеры для semplicity) и произвольную перспективу плоскость. Он говорит, что мне нужно будет компенсировать позиции пространства X, Y вершин вершин на E_x и E_y соответственно.

Я не могу понять этот отрывок, как я должен использовать переменную точку зрения, изменяющую только смещения X, Y?

Редактировать: может быть что-то вроде этого?

#version 330 

layout(location = 0) in vec4 position; 
layout(location = 1) in vec4 color; 

smooth out vec4 theColor; 

uniform vec2 offset; 
uniform vec2 E; 
uniform float zNear; 
uniform float zFar; 
uniform float frustumScale; 


void main() 
{ 
    vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0); 
    vec4 clipPos; 

    clipPos.xy = cameraPos.xy * frustumScale + vec4(E.x, E.y, 0.0, 0.0); 

    clipPos.z = cameraPos.z * (zNear + zFar)/(zNear - zFar); 
    clipPos.z += 2 * zNear * zFar/(zNear - zFar); 

    clipPos.w = cameraPos.z/(-E.z); 

    gl_Position = clipPos; 
    theColor = color; 
} 

Edit2: благодаря Борису, ваша картине помогла много :) особенно потому, что:

  • это делает ясно, что вы ранее заявляли о мыслительных Е как проекция месте положения и не положения точки глаза
  • он подчеркивает, что размер проектной плоскости должен быть всегда [-1, 1], прохождение, которое я прочитал в книге, не до конца понимая, что это значит

J У вас любопытство, почему вы упоминаете умножение после вычитания? По той же причине, по словам книги, это соотношение сторон? Потому что все логически толкает меня делать прямо противоположное, это первый перевод (-2), а затем умножение (/ 5) .. Или, может быть, с термином «масштабирование», книга относится к функции перестановки?

+1

Я отредактировал свой ответ, улучшив то, что я изначально написал, и добавив объяснение с реальным кодом и цифрой, иллюстрирующей то, что я думаю, задано в книге. – Boris

+0

Рад, что это помогло. Я умножаю затем вычитание, так как это правильный результат: -P Помните, что в вашем NDC цветная область является кубом единицы: границы X красной области в верхнем правом рисунке составляют 1/5 и 3/5 (это соотношение где серые линии пересекают синюю плоскость проекции в верхнем левом рисунке). Затем, если вы сделаете то, что предлагаете применить к этим двум значениям {1/5 | 3/5}, вы получите: ({1/5 | 3/5} - 2) * 5 = {-9; -7}. И если вы сделаете это в правильном порядке: ({1/5 | 3/5} * 5) - 2 = {-1; 1} :-) – Boris

+0

Кстати, плоскость проекции не имеет - размер [-1; 1]. Это просто соглашение, принятое в книге: автор предпочитает масштабировать пространство до (scaleFrustrum), что эквивалентно масштабированию плоскости проектирования (если только E.xy! = 0, я на самом деле не учел это в моем код...). Обратите внимание, что Ez и frustrumScale являются избыточными: перемещение плоскости проекции дальше от глаза равносильно уменьшению его размера, что эквивалентно увеличению frustrumScale (эквивалентно масштабированию) – Boris

ответ

5

Здесь нас интересует вычисление преобразования координат камеры (CC) в координаты нормализованных устройств (NDC).

Подумайте о E как о положении плоскости проекции в координатах камеры, а не о положении точки глаз в соответствии с плоскостью проекции. В координатах камеры точка обзора по определению находится в начале координат, по крайней мере, в моей интерпретации «Координата камеры» означает: координатный кадр, ориентированный от того места, где вы смотрите на сцену. (Вы можете математически определить перспективное преобразование, центрированное из любого места, но это означает, что ваше пространство для входа не является пространством камеры, imho. Это то, к чему стремится трансформация World-> Camera, как вы увидите в chapter 6)

Резюме :

  • вы находитесь в пространстве камеры, следовательно, ваша точка глаза находится в точке (0,0,0)
  • вы смотрите в стороне отрицательного Z-оси
  • проекционной плоскости параллелен хОу плоскость с размером [-1,1] в обоих направлениях

Это изображение здесь (каждый тик равен 0,5 единицы):

enter image description here

На этой картинке вы можете видеть, что плоскость проекции (нижняя часть серой трапеции) находится в центре (0 , 0, -1) с размером [-1,1] в обоих направлениях X и Y.

Теперь, вместо того чтобы выбрать (0,0, -1) для центра этой плоскости, выбрать произвольное (E.x, E.y, E.z) положение (предполагается, что E.z отрицательно). Но плоскость все еще должна быть параллельна оси xOy и того же размера.

Вы можете видеть, что размер E.xy играет совсем другую роль, чем E.z, причина, по которой E.xy будет вовлечена в вычитание, тогда как E.z будет вовлечена в деление. Это легко увидеть на примере:

  1. предположить zNear = -ez (не обязательно так, но вы можете на самом деле всегда изменить frustumScale иметь эквивалентную перспективу, удовлетворяющую этим)
  2. Рассмотрим точку Е (который является центром плоскости проекции).

Какова его координата в пространстве НДЦ? Это (0,0, -1) по определению. То, что вы сделали, - это вытеснение E.xy, но деление на -E_z.

Ваш код получил эту идею, но все-таки некоторые вещи неправильно:

  1. Во-первых, вы определили uniform vec2 E; вместо uniform vec3 E; (просто опечатка, не имеет большого значения)
  2. Линия clipPos.xy = ... ; о vec2 арифметика. Следовательно, вы можете умножать только скалярные значения (т. Е. Float) или добавлять/вычитать значения vec2. Следовательно, vec4(E.x, E.y, 0.0, 0.0) имеет неправильный тип, вместо этого вы должны использовать E.xy, который имеет правильный тип vec2.
  3. Вы должны на самом деле вычесть E.xy, а не добавлять его. Это легко увидеть в моем примере выше.
  4. Наконец, все более тонкие ;-)

Я сделал картину для иллюстрации изменения:

enter image description here

Каждый тик 1 единица в этой картинке. В верхнем левом углу находится ваше координатное пространство камеры с отображаемыми zNear, zFar и двумя возможными проекционными плоскостями. В синем - тот, который используется в объяснении и шейдере here, а красный - тот, который вы сейчас хотите использовать. Цветные области соответствуют тому, что должно быть видно на вашем последнем экране, например. что должно быть в кубе [-1,1]^3 в пространстве НДЦ. Следовательно, если вы используете синюю плоскость проекции, вы хотите получить пространство в правом верхнем углу, и если вы используете красную проекционную плоскость, вы хотите выбрать пространство внизу. Для этого вы можете заметить, что вам необходимо выполнить масштабирование и перевод в пространстве NDC, например. после перспективного деления! (Я думаю, что то, что написано в книге, либо неверно, либо интерпретирует вопрос по-разному).

Следовательно, вы хотите сделать это в Координата euclidean (т. Е. Не однородная координата, например.без W координат):

clipPosEuclideanRed.xy = clipPosEuclideanBlue.xy * (-E.z) - E.xy; 
clipPosEuclideanRed.z = clipPosEuclideanBlue.z; 

Однако, поскольку вы в однородных координатах, это значения, на самом деле:

clipPosEuclidean.xyz = clipPos.xyz/clipPos.w; // with clipPos.w = -cameraPos.z; 

Таким образом, вы должны composate написав:

clipPosRed.xy = clipPosBlue.xy * (-E.z) - E.xy * (-cameraPos.z); 
clipPosRed.z = clipPosBlue.z; 

Поэтому моим решением этой проблемы было бы добавить только одну строку:

void main() 
{ 
    vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0); 
    vec4 clipPos; 

    clipPos.xy = cameraPos.xy * frustumScale; 

    // only add this line 
    clipPos.xy = - clipPos.xy * E.z + E.xy * cameraPos.z; 

    clipPos.z = cameraPos.z * (zNear + zFar)/(zNear - zFar); 
    clipPos.z += 2 * zNear * zFar/(zNear - zFar); 

    clipPos.w = -cameraPos.z; 

    gl_Position = clipPos; 
    theColor = color; 
} 
+0

Привет, Борис, спасибо за ваш длинный ответ .. да, извините, я имел в виду (0 , 0, 0) относительно точки глаз. Поэтому я должен иметь плоскость проекции всегда параллельно оси xOy. Я попробую, чтобы – elect

+0

«* Во-первых, вопреки тому, что вы пишете, точка глаза всегда фиксируется в (0,0,0). *« Чепуха. Вы можете создать [перспективную проекцию из произвольного местоположения] (http://en.wikipedia.org/wiki/3D_projection#Perspective_projection). Это просто, что * стандартная * матрица фиксирует его в начале координат, чтобы сделать математику проще. Он не должен быть в начале. –

+0

Да, я знаю, но я просто использую конвенцию используемой книги, чтобы сделать вопрос понятным в контексте объяснения, приведенного в книге. В любом случае, это хороший момент. – Boris

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

  • Нет связанных вопросов^_^