Білборд це 2д річ в трьохвимірному світі. Не 2д меню поверх всього, не 3д площина, яку Ви можете повертати - це щось проміжне, як “смужка життя” в більшості ігор.

Їх відрізняє те, що вони позиціонуються в визначених місцях, але їх орієнтація розраховується так, що б вони були завжди повернуті лицем до камери.

Рішення №1 : 2д спосіб

Це спосіб дуже простий.

Просто розрахуйте положення на екрані і показуйте 2д текст (дивіться туторіал 11) в цій позиції.

// Все це вже було пояснено в 3 туторіалі. Нічого нового.
glm::vec4 BillboardPos_worldspace(x,y,z, 1.0f);
glm::vec4 BillboardPos_screenspace = ProjectionMatrix * ViewMatrix * BillboardPos_worldspace;
BillboardPos_screenspace /= BillboardPos_screenspace.w;

if (BillboardPos_screenspace.z < 0.0f){
    // Об'єкт за камерою, не показуємо.
}

Та-да!

З позитивного - цей метод дуже простий і білборд буде мати одні й тіж розміри не залежно від відстані до камери. Але 2д текст завжди відображається поверх всього іншого і це може/буде спотворювати процес малювання.

Рішення №2 : 3д спосіб

Цей спосіб зазвичай значно кращий і не сильно складніший.

Ціль в тому, що б тримати меш вирівняним по відношенню до камери, навіть коли камера переміщується:

Вми можете бачити проблему в розрахунку правильної матриці моделі, але це все рівно дуже просто.

Ідея в тому, що кожний кут білборда знаходиться в центрі, зміщеного векторами камери вгору на вниз:

Звичайно, ми знаємо тільки позицію центра білборда в світових координатах, тому ми також потребуємо векторів “вгору” та “праворуч” для камери в цих координатах.

В просторі камери вектор вгору це (0,1,0), Для отримання світових координат, просто домножте на матрицю, що перетворює простір камери в світові координати, що насправді є інвертованою матрицею виду.

Ось простий спосіб це зробити:

CameraRight_worldspace = {ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]}
CameraUp_worldspace = {ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]}

Як тільки у нас це є, дуже легко розрахувати кінцеву позицію вершини:

vec3 vertexPosition_worldspace =
    particleCenter_wordspace
    + CameraRight_worldspace * squareVertices.x * BillboardSize.x
    + CameraUp_worldspace * squareVertices.y * BillboardSize.y;
  • particleCenter_worldspace як видно з імені, позиція центру білборду. Вона вказана в uniform vec3.
  • squareVertices це оригінальний меш. squareVertices.x is -0.5 для лівих вершин, які в результаті переміщуються вліво відносно камери (через *CameraRight_worldspace)
  • BillboardSize - це розмір в світових координатах білборда, отримується через іншу uniform змінну.
І ось результат. Це ж дійсно просто ?

Для запису, ось як squareVertices отримано:

// VBO містить 4 вершини частинок.
 static const GLfloat g_vertex_buffer_data[] = {
 -0.5f, -0.5f, 0.0f,
 0.5f, -0.5f, 0.0f,
 -0.5f, 0.5f, 0.0f,
 0.5f, 0.5f, 0.0f,
 };

Рішення №3 : Фіксований 3д розмір

Як Ви можете побачити вище, розмір білборда змінюється відповідно до відстані від камери. Це очікуваний результат в деяких випадках, але в інших (таких як смужка життя), Ви можете хотіти зафіксувати розмір.

Так як зміщення між центром і межами білборда повинні бути фіксованими в просторі екрану, ось що ми будемо робити - розрахуємо позицію центра в координатах екрану і змістимо їх.

vertexPosition_worldspace = particleCenter_wordspace;
// Отримаємо центр екрана для центру частинки
gl_Position = VP * vec4(vertexPosition_worldspace, 1.0f);
// Тут ми повинні самостійно зробити перспективний поділ.
gl_Position /= gl_Position.w;

// Перемістимо вершину в екранних координатах. Там не потрібні вектори камери.
gl_Position.xy += squareVertices.xy * vec2(0.2, 0.05);

Пам’ятайте, що на цьому етапі малювання, Ви знаходитись в нормалізованих координатах пристрою, тобто в межах -1..1 по обох осях, це не пікселі!

Якщо Вам потрібен розмір в пікселях, це просто - використовуйте (ScreenSizeInPixels / BillboardSizeInPixels), а не BillboardSizeInScreenPercentage.

Рішення №4 : Тільки вертикальний поворот

Деякі системи моделюють далекі дерева і лампи як білборди. Але Ви точно не хочете, що б Ваші дерева були скрученими - вони повинні бути вертикальними. Отже потрібна гібридна система, яка буде повертати тільки навколо однієї вісі.

Але це вже вправа для читача!