Frustum Culling (Отсечение по пирамиде видимости) (комментарии)
Это сообщение сгенерировано автоматически.
Возник вопрос, вот по первой ссылке код:
/* ЗАДНЯЯ плоскость */ frustum[4][0] = clip[ 3] - clip[ 2]; frustum[4][1] = clip[ 7] - clip[ 6]; frustum[4][2] = clip[11] - clip[10]; frustum[4][3] = clip[15] - clip[14]; /* ПЕРЕДНЯЯ плоскость */ frustum[5][0] = clip[ 3] + clip[ 2]; frustum[5][1] = clip[ 7] + clip[ 6]; frustum[5][2] = clip[11] + clip[10]; frustum[5][3] = clip[15] + clip[14];
Третье число в каждой плоскости это параметр С с уравнения
Когда я подставляю точку (0,0,30), формуле if( frustum
[0] * x + frustum
[1] * y + frustum
[2] * z + frustum
[3] <= 0 ) всегда говорит что для передней плоскости все ок, точка перед ней, но про заднюю говорит что точка за ней.
Все потому что параметр С для противоположных плоскостей с разным знаком.
Проекционную матрицу считаю так:
auto aspectRatio = (float)realWidth / ( float)realHeight; const float PI = 3.14159265359f; const float TORAD = PI / 180.0f; float fov = 45.0f; float nearZ = 0.1f; float farZ = 1000.0f; float t = 1.0f / tan( fov * TORAD * 0.5f); float nf = nearZ - farZ; _mProject = Mat4( t / aspectRatio, 0, 0, 0, 0, -t, 0, 0, 0, 0, ( -nearZ - farZ) / nf, ( 2 * nearZ*farZ) / nf, 0, 0, 1, 0);
Есть подозрения, что где-то я ошибся в матрице, но рендерит все обьекты нормально.
UPD: Проверил на листике, похоже пропустил минус на 10 елементе, вечером проверю...
Anders333
Советую выкинуть данную статью, и все ссылки в ней, по одной простой причине.
После вычисления проекции точки, посредством умножения ее на матрицу PROJ*MODEL, проверка ее попадания в пирамиду происходит одним выражением flag==0 и все!
// умножение вектора на матрицу r[0]=_invector[0]*_matrixa[0]+_invector[1]*_matrixa[4]+_invector[2]*_matrixa[8]+_invector[3]*_matrixa[12]; r[1]=_invector[0]*_matrixa[1]+_invector[1]*_matrixa[5]+_invector[2]*_matrixa[9]+_invector[3]*_matrixa[13]; r[2]=_invector[0]*_matrixa[2]+_invector[1]*_matrixa[6]+_invector[2]*_matrixa[10]+_invector[3]*_matrixa[14]; r[3]=_invector[0]*_matrixa[3]+_invector[1]*_matrixa[7]+_invector[2]*_matrixa[11]+_invector[3]*_matrixa[15]; // интересующая нас часть про отсечение по пирамиде видимости для точки r[4]=-r[3]; // коэффициент указывающий на размеры среза пирамиды видимости в плоскости параллельной плоскости проекции пересекающей проецируемую точку. int flag=0; if (r[0]>r[3]) flag|=0x01; // правая плоскость if ( r[1]>r[3]) flag|=0x02; // верхняя плоскость if ( r[2]>r[3]) flag|=0x04; // дальняя плоскость if ( r[0]<r[4]) flag|=0x10; // левая плоскость if ( r[1]<r[4]) flag|=0x20; // нижняя плоскость if ( r[2]<r[4]) flag|=0x40; // ближайшая плоскость
или
((r[0]>=r[4] && r[0]<=r[3]) && (r[1]>=r[4] && r[1]<=r[3]) && (r[2]>=r[4] && r[2]<=r[3]))
Прошло ровно 11 лет с написания этой статьи, и вдруг внезапно появились комментарии. Откуда они берутся?
gammaker
Ж))
Меня больше заботит, удивляет, вводит в недоумение, нелепость данной статьи и высокая должность авторов подобного.
И с последствием влияния таких "кадров" приходиться бороться по сей день.
foxes
Там ровно то же самое, что и у тебя.
foxes
спасибо, я думал насчет проектирования, но с уравнениями плоскости меньше действий происходит, собственно меньше нагрузки на CPU.
В общем, с директ матрицами всё работало. А если создаю сам матрицу вида и проекции, получается фигня с плоскостью. Наверно прийдется всё-таки использовать проекцию точки=(
Blew_zc
> Там ровно то же самое, что и у тебя.
Там общее описание, говорящее о том что через вычисление плоскостей работает быстрее чем через проекцию, и куча ссылок на бредовые вычисления с 16 делениями. В общем то последние оптимизаторы это хорошо обрабатывают и незаметно для программиста приводят все к простой формуле о которой я говорю.
Вкратце отсечение вершины плоскостью это простое выражение:
dot(vertex-plane,normal)<0 отсечена. для пирамиды таких 6 - бессмысленных вычислений. Помимо этого нужно еще сами значения нормалей плоскостей вычислять.
И ни в одной из ссылок не говориться о том что достаточно умножить вершину на матрицу чтобы выполнить отсечение - а это всего 4 dot(vector,matrix(i)).
А в самой же статье делается акцент вот на чем:
На практике удобно использовать первый вариант: найти уравнения всех плоскостей пирамиды (это можно сделать из матрицы) и проверить, находится ли точка перед этими плоскостями.
Это совершенно обратное тому что я говорю. А говорю я, о том что вычисление проекции не только быстрее и проще но и равносильно вычислению с помощью плоскостей также как:
a-b=a-b+c*2-d*3+d-c*2+d*2...
Кроме того ни где не описывается как сделать расчет с помощью матрицы если основание пирамиды трапеция.
Также ни где не описывается проблема деревьев, которые с легкостью можно заменить на сетку и получить большую производительность и более простой код. А использование нескольких сеток разной детализации даст и производительность и реализацию улучшенного алгоритма того самого дерева.
Ни где не говориться о том что эти самые простые решения, которые можно описать в двух словах, будут и быстрее работать и понятнее любому для реализации.
А вся та байда с картинками по сути ни чего не даст, кроме, головной боли читающим и пьедестал пишущим! И ни какой практической пользы.
Anders333
> А если создаю сам матрицу вида и проекции, получается фигня с плоскостью.
Для того чтобы выполнить отсечение через расчет проекции нет нужды в видовой матрице, нужна только проекционная и модельная, другие вычисления не нужны.
foxes
Уточнение. Это для OpenGL clip space пример. Для DirectX clip space нужно последнюю строчку:
if (r[2]<r[4]) flag|=0x40; // ближайшая плоскость
заменить на:
if (r[2]<0) flag|=0x40; // ближайшая плоскость
MrShoor
Да, или вычислять одинаковые проекционные матрицы для GL и DX в ручную для данного примера - ни каких проблем. Вообще разница между DX и GL это изменение мест слагаемых и названий, что создает путаницу Row/Coll хотя на низком уровне ориентация у матриц одинаковая.
по ссылке:
foxes
> Конечно там все замечательно написано но только про саму матрицу проекции. Для
> примера буду рассматривать OpenGL.
Anders333
> А если создаю сам матрицу вида и проекции, получается фигня с плоскостью.
Anders333
> _mProject = Mat4(
> t / aspectRatio, 0, 0, 0,
> 0, -t, 0, 0,
> 0, 0, (-nearZ - farZ) / nf, (2 * nearZ*farZ) / nf,
> 0, 0, 1, 0);
вот тут как раз за счет перепутанной ориентации Row/Coll (строка/столбец) может быть и не работает. Попробуй транспонировать.
Anders333
> но с уравнениями плоскости меньше действий происходит, собственно меньше
> нагрузки на CPU.
неа.
foxes
> Да, или вычислять одинаковые проекционные матрицы для GL и DX в ручную для
> данного примера - ни каких проблем. Вообще разница между DX и GL это изменение
> мест слагаемых и названий, что создает путаницу Row/Coll хотя на низком уровне
> ориентация у матриц одинаковая.
В инете вообще жесть, одни пишут что матрицы кроме транспонирования для ДХ и ОГЛ еще и способом отличаются.
> вот тут как раз за счет перепутанной ориентации Row/Coll (строка/столбец) может
> быть и не работает. Попробуй транспонировать.
Ну как мне обьяснили, можно люые матрицы поекции юзать. Я рендерю на Вулкане, а модельки импортирую с блендера, поэтому решил использовать матрицы как в ОГЛ. Да и рендерит прекрасно. Надо будет еще почитать про плоскости, а то немного непонятен принцып извлечения плоскостей с матрицы.
И спасибо за ссылку, ща почитаю.
foxes
> неа.
есть ОББ, у него 8 вершин. Для проецирования нужно 8 точек умножить на матрицу на. С плейнами для каждой точки надо произвести только 3 умножения и 4 суммирования.
Anders333
> С плейнами для каждой точки надо произвести только 3 умножения и 4
> суммирования.
Помножить на 6 забыл. Плоскостей же 6.
MrShoor
> Помножить на 6 забыл. Плоскостей же 6.
Блин, точно. Надо будет потестить сегодня на своих 2,5к обьектах, что быстрее получится, проецирование или проверка с плейнами.
Anders333
> Для проецирования нужно 8 точек умножить на матрицу на.
используй сферу - достаточно одного умножения на матрицу.
foxes
> dot(vertex-plane,normal)<0 отсечена. для пирамиды таких 6 - бессмысленных
> вычислений.
foxes
> достаточно умножить вершину на матрицу чтобы выполнить отсечение - а это всего
> 4 dot(vector,matrix(i)).
условия такие
if (( r[0]-r[3])/proj.x.x>-radius) flag|=0x01; // правая плоскость if ( ( r[1]-r[3])/proj.y.y>-radius) flag|=0x02; // верхняя плоскость if ( ( r[2]-r[3])/proj.z.z>-radius) flag|=0x04; // дальняя плоскость if ( ( r[0]+r[3])/proj.x.x<radius) flag|=0x10; // левая плоскость if ( ( r[1]+r[3])/proj.y.y<radius) flag|=0x20; // нижняя плоскость if ( ( r[2]+r[3])/proj.z.z<radius) flag|=0x40; // ближайшая плоскость
foxes
Хочу сделать по сфере, но немного непонял про матрицу с нормалями плейнов внутри. Как туда нормали записать? Или это обычная матрица вида умноженная на проекционную?
Еще вопрос про эту матрицу, с которой плейны вытаскивают. У нее нормали в глобальной системе координат или переходят в локальную камеры?
Тема в архиве.