2015-01-26 3 views
3

После прочтения datenwolf's 2011 answer concerning tile-based render setup in OpenGL я попытался реализовать его решение. Исходное изображение выглядит следующим образом (при 800 х 600)Настройка матрицы OpenGL для черепичного рендеринга

Original image

Полученное изображение с 2х2 плиток, каждая плитка при 800 х 600 на плитке выглядит следующим образом.

Resulting 4 images joined together

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

Я делаю 4 прохода, где:

w, h are 2,2 (2x2 tiles)  
x, y are (0,0) (1,0) (0,1) and (1,1) in each of the 4 passes  
MyFov is 1.30899692 (75 degrees) 
MyWindowWidth, MyWindowHeight are 800, 600 
MyNearPlane, MyFarPlane are 0.1, 200.0 

алгоритм для вычисления усеченный для каждой плитки:

auto aspect = static_cast<float>(MyWindowWidth)/static_cast<float>(MyWindowHeight); 
auto right = -0.5f * Math::Tan(MyFov) * MyShaderData.Camera_NearPlane; 
auto left = -right; 
auto top = aspect * right; 
auto bottom = -top; 
auto shift_X = (right - left)/static_cast<float>(w); 
auto shift_Y = (top - bottom)/static_cast<float>(h); 
auto frustum = Math::Frustum(left + shift_X * static_cast<float>(x), 
          left + shift_X * static_cast<float>(x + 1), 
          bottom + shift_Y * static_cast<float>(y), 
          bottom + shift_Y * static_cast<float>(y + 1), 
          MyShaderData.Camera_NearPlane, 
          MyShaderData.Camera_FarPlane); 

, где Math :: Frustum является:

template<class T> 
Matrix4x4<T> Frustum(T left, T right, T bottom, T top, T nearPlane, T farPlane) 
{ 
    Matrix4x4<T> r(InitialiseAs::InitialiseZero); 

    r.m11 = (static_cast<T>(2) * nearPlane)/(right - left); 
    r.m22 = (static_cast<T>(2) * nearPlane)/(top - bottom); 
    r.m31 = (right + left)/(right - left); 
    r.m32 = (top + bottom)/(top - bottom); 
    r.m33 = -(farPlane + nearPlane)/(farPlane - nearPlane); 
    r.m34 = static_cast<T>(-1); 
    r.m43 = -(static_cast<T>(2) * farPlane * nearPlane)/(farPlane - nearPlane); 

    return r; 
} 

Для полноты моего матраса матраса 4x4:

struct 
{ 
    T m11, m12, m13, m14; 
    T m21, m22, m23, m24; 
    T m31, m32, m33, m34; 
    T m41, m42, m43, m44; 
}; 

Может ли кто-нибудь указать мою ошибку?

Edit:

Так derhass объяснил мне - гораздо более простой способ делать вещи просто масштабировать и перевести проекционную матрицу. Для тестирования я изменил мою матрицу перевода, расширены в 2 раза, следующим образом (изменение перевода для каждой плитки):

auto scale = Math::Scale(2.f, 2.f, 1.f); 
auto translate = Math::Translate(0.5f, 0.5f, 0.f); 
auto projection = Math::Perspective(MyFov, 
            static_cast<float>(MyWindowWidth)/static_cast<float>(MyWindowHeight), 
            MyShaderData.Camera_NearPlane, 
            MyShaderData.Camera_FarPlane);   

MyShaderData.Camera_Projection = scale * translate * projection; 

Полученное изображение ниже (сшивание 4 вместе) - разрывы в изображении вызвано я думаю, что это будет другая проблема, с которой мне придется иметь дело в какой-то момент.

Resulting image

+0

Я не проверил, что это неправильно в вашей реализации, но я думаю, что решение этого datenwolf там ненужно комплекс. Если вы визуализировали сцену с некоторой матрицей проекций (независимо от ортогональности или перспективы), полученный усеченный конус окажется в однородном представлении пространства [-1,1]^3 НДЦ. Поэтому, если вы хотите, чтобы какая-либо часть этого отображаемого полноэкранного экрана была достаточной, просто _pre-multiply_ некоторый масштаб и перевод по x и y, чтобы выбрать любой 2D-прямоугольник, который вам нравится (что будет иметь тот же эффект, что и изменение FOV и асимметрии в перспективном усечении). – derhass

+0

Я думал, что НДЦ произошел после гомогенного разрыва, который после умножения на матрицу проекции, поэтому я не вижу, как это будет работать. Независимо от того, что я пробовал использовать масштаб WxH и различные переводы, и я не мог заставить его работать. Математика ошибочна. – Robinson

+0

Я предлагаю применить в пространстве клипа. Я только собираю NDC для диапазона [-1,1] усеченного конуса. Ключевым моментом является применение простого перевода и масштабирования после применения матрицы проецирования (что означает, что _pre_ умножает его на стандартные соглашения GL) для масштабирования и смещения некоторого суб-прямоугольника [-1,1] до полного [-1, 1] точно отобразит эту часть изображения в полном окне просмотра. – derhass

ответ

3

Это не реальный ответ на вопрос, но это может быть полезным альтернативный подход к тому, что вы пытаетесь решить здесь. На мой взгляд, решение datenwolf в его ответе на stackoverflow question, о котором вы говорите, более сложное, чем это должно быть. Поэтому я представляю свою альтернативу здесь.

Forword: Я принимаю стандартные соглашения о матрице OpenGL, так что преобразование вершин с матрицей M выполняется как v'= M *v (как и в случае с фиксированной функцией).

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

Ключевым моментом является то, что объем просмотра определяется как кубик [-1,1]^3 в пространстве NDC. Пространство клипа (это то, что P преобразует данные) является просто однородным представлением этого тома.Поскольку типичные матрицы преобразования 4x4 все работают в однородном пространстве, нам действительно не нужно заботиться о w и просто может определять преобразования, как если бы мы были в пространстве NDC.

Поскольку вам нужно только двумерное черепица, z следует оставить как есть, и требуется только некоторая шкала и перевод в x и y. При составлении преобразований A и B в одну матрицу C в качестве C=A*B, в соответствии с вышеупомянутыми соглашениями, это приводит к тому, что применяется сначала B, а A последнее (начиная с C*v == A*B*v == A*(B*v)). Таким образом, чтобы изменить результат после проекции, мы должны предварительно -кратно некоторых преобразований P и мы сделали:

P'=S(sx,sy,1) * T(tx,ty,0) * P 

Строительство P' будет работать с любой действительной матрицы проекции P, независимо от того, если это перспектива или ортотрансформация. В орто-случае это совершенно ясно. В перспективном случае это фактически изменяет как поле зрения, так и сдвигает усечку на асимметричную.

Если вы хотите поместить изображение в сетку m раз n сегментов. ясно, что sx=m и sy=n. Так как я использовал S * T (по выбору), T применяется до шкалы, поэтому для каждой плитки (tx,ty) - это просто вектор, перемещающий центр плитки в новый центр (который будет происходить). В НДЦ пространство 2 единицы в ширину и в высоту, для плитки x,y, трансформация

tx= - (-1 + 2/(2*m) + (2/m) * x) 
ty= - (-1 + 2/(2*n) + (2/n) * y) 
// ^ ^  ^ 
//  |  |   | 
//  |  |   +- size of of each tile in NDC space 
//  |  | 
//  |  +- half the size (as the center offset) 
//  | 
//  +- left/bottom border of NDC space 
+0

Спасибо за вашу помощь в этом дергасе. Я ценю это. – Robinson

+1

ничего себе, этот ответ действительно хорош! ты спас мой день! +1! – Thomas

+0

Кстати, если вы используете дополнительные отсечения, это решение будет работать некорректно. – Thomas