Гугли статьи, читай комментарии в исходниках.
Я сомневаюсь, что кто-то тут всё бросит и начнёт читать лекцию об устройстве BSP в 3д-играх. Хотя кто знает?
Ну блин, я бы не отказался)
Пойду сам разберусь.
Оно мне в принципе и не надо, но для общего развития пригодилось бы. Тогда вопрос:
Движок то старый, разчитан на медленные видяхи, есть ли смысл проверять невидимые участки карты - сама проверка не займет ли больше времени чем рисование ??
n00b писал: сама проверка не займет ли больше времени чем рисование ??
Смотря какая проверка и смотря что рисовать. Если рендер уровня кваки - то по-моему разницы никакой, в любом случае будет фпс, упёртый в потолок. Если же куча всяких "тяжёлых" эффектов... Ну тут надо учесть, что большинство нубских говнодвижков вроде моей волатилы являются CPU-bound на уровне драйвера, и нагрузка на CPU очень большая. Помогает многопоточный SMP-рендерер - расчеты видимости делает один процессор, а в это время второй процессор засылает данные в драйвер.
n00b писал: До цикла мне всё понятно, а что делает это условие ?
C++ Source Code:
if (vis[i>>3] & (1<<(i&7)))
виз в целях экономии места хранится побитно. каждый бит определяет видимость того или иного визблока из другого визблока. Соответственно еденичка - виден, ноль - нет. мега-условие, это собственно доступ к нужному биту.
Цитата:
n00b писал: Дальше непонятно почему node приравнивается листу:
C++ Source Code:
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
это сделано для удобства. В первой и второй кваке, ноды и листья линкуются в общую цепь и имеют сходные структуры примерно до середины. Там есть комментарии, что вот эта часть расшарена между ноадами и лифами. а эта - уникальна для лифов или нодов.
Таким образом мы бегаем по лифам, пока не наткнемся на ноду или наоборот. А чтобы заведомо отличить лиф от ноды, мы делаем либо plane == NULL (так сделано в даркплейсе), либо contents == 0 (как в оригинальной кваке).
Цитата:
n00b писал: И что за кадры ( visframe ) там используются и для чего они нужны.
это чтобы не бегать по лифам каждый кадр, а только при смене визблока.
А визблок меняется, ориентировочно каждые 100 юнитов (точно не помню). Таким образом мы сохраняем указатель на старый лиф в r_oldviewleaf и проверяем его с новым лифом (который получается из vieworigin игрока) если лифы совпадают (т.е. игрок находится по прежнему в том же самом лифе), то визфрейм не инкрементится и остается старым. Если же лиф сменился, мы просто помечаем видимые ноды новым значением (а все остальные ноды остаются либо вообще не помеченные, либо помеченные устаревшим значением visframecount) и далее есть проверка на визфрейм, где мы просто отсекаем невидимые ноды и листья.
Цитата:
XaeroX писал: Я сомневаюсь, что кто-то тут всё бросит и начнёт читать лекцию об устройстве BSP в 3д-играх
Йолки-палки! На форуме появился человек, которому действительно интересное в чём-то разобраться, а не украсть рендер паранои, а ты его отпугиваешь.
Я тут решил разбить все плоскости карты на треугольники.
Треугольники делаю по рёбрам фейса, точки плоскости беру методом из quake 1: ( рисует фейсы по крайней мере правильно )
И разбиваю на треугольники с точками:
точка1, точкаN, точкаN + 1;
Разбивание происходит, но не всегда верно. Вот например пятиугольник, разбивается совсем не на 3 триугольника как надо бы. По рисунку видно, что линии соединяются с точками других плоскостей, получается что даже на 1 прямой фейса может быть несколько ребер и их надо склеивать, или всё же неверен алгоритм разбивания ?
n00b писал: Я тут решил разбить все плоскости карты на треугольники.
ну MarkLeaves тут совершенно не нужен. То есть вообще.
Кроме того, для разбиения на треугольники крайне желательно генерить индексы для вертексов. Потому что по сути, сами вертексы трогать не следует.
Ну вот простенький код для разбиения полигона на треугольники.
Простенький - потому что не учитывает такие интересные вещи, как например subdivided surface - т.е. воду, лаву и прочие жидкости.
C++ Source Code:
1
/*
2
=================
3
Mod_BuildPolygon
4
=================
5
*/
6
staticvoid Mod_BuildPolygon( msurface_t *surf, int numVerts, constfloat *verts )
for( i = 0, index = 2; i < mesh->numElems; i += 3, index++ )
46
{
47
mesh->elems[i+0] = 0;
48
mesh->elems[i+1] = index - 1;
49
mesh->elems[i+2] = index;
50
}
51
52
// setup normal
53
if( surf->flags & SURF_PLANEBACK )
54
VectorNegate( surf->plane->normal, normal );
55
else VectorCopy( surf->plane->normal, normal );
56
57
VectorNormalize( normal );
58
59
// create vertices
60
mesh->numVerts = numVerts;
61
62
for( i = 0; i < numVerts; i++, verts += 3 )
63
{
64
// vertex
65
VectorCopy( verts, mesh->vertexArray[ i ] );
66
VectorCopy( normal, mesh->normalsArray[ i ] );
67
68
mesh->vertexArray[ i ][3] = 1.0f;
69
mesh->normalsArray[ i ][3] = 1.0f;
70
71
// texture coordinates
72
s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3];
73
if( texinfo->width != -1 ) s /= texinfo->width;
74
else s /= surf->shader->stages[0].textures[0]->width;
75
76
t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3];
77
if( texinfo->height != -1 ) t /= texinfo->height;
78
else t /= surf->shader->stages[0].textures[0]->height;
79
80
mesh->stCoordArray[ i ][0] = s;
81
mesh->stCoordArray[ i ][1] = t;
82
83
// lightmap texture coordinates
84
s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->textureMins[0];
85
s += surf->lmS * LM_SAMPLE_SIZE;
86
s += LM_SAMPLE_SIZE >> 1;
87
s /= LIGHTMAP_TEXTURE_WIDTH * LM_SAMPLE_SIZE;
88
89
t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->textureMins[1];
90
t += surf->lmT * LM_SAMPLE_SIZE;
91
t += LM_SAMPLE_SIZE >> 1;
92
t /= LIGHTMAP_TEXTURE_HEIGHT * LM_SAMPLE_SIZE;
93
94
mesh->lmCoordArray[ i ][0] = s;
95
mesh->lmCoordArray[ i ][1] = t;
96
}
97
}
Этот же код в чуть более другой вариации можно встретить в различных проектах на тему Q2 и Q3: Quake2 Evolved, QFusion, EGL и прочих.
Конкретно этот код - взят из раннего ксаша (конец 2010 года).
Добавлено 19-03-2011 в 20:12:
Структурка mesh_t выглядит вот так, если интересно
C++ Source Code:
1
typedefstruct mesh_s
2
{
3
int numVerts;
4
int numElems;
5
6
vec4_t *vertexArray;
7
vec4_t *normalsArray;
8
vec2_t *stCoordArray;
9
vec2_t *lmCoordArray;
10
rgba_t *colorsArray;
11
elem_t *elems;
12
13
struct mesh_s *next; // temporary chain of subdivided surfaces
Структурка mesh_t выглядит вот так, если интересно
Конечно интересно
Все сделал, работает не плохо.
Перевел всё на вершинные буфера - на карте de_dust2 3000+ fps за место 280 через glBegin\glEnd.
Добавлено 20-03-2011 в 11:22:
И сразу вопрос по VBO:
Можно ли без опасений использовать вершинные буфера, или все-таки ещё есть видеоустройства, которые их не поддерживают? ( например ноутбуки )
LIGHTMAP_TEXTURE_WIDTH и LIGHTMAP_TEXTURE_HEIGHT равны размеру твоих лайтмап в движке. Обычно это 256 х 256, халфа использует 128х128. LM_SAMPLE_SIZE - 16 (захардкоденное значение разрешения лайтмапы для хл1\ку1\ку2). Менять нельзя ни в коем случае.
Цитата:
n00b писал: Перевел всё на вершинные буфера - на карте de_dust2 3000+ fps за место 280 через glBegin\glEnd.
с такой маааленькой поправкой - без переключения текстур, без освещения, без студиомоделей и вообще без эдиктов.
А как только ты всё это нарисуешь, у тебя всё вернется обратно на круги своя.
Цитата:
n00b писал: Можно ли без опасений использовать вершинные буфера, или все-таки ещё есть видеоустройства, которые их не поддерживают?
вертекс арраи везде поддерживаются. VBO не везде, к тому же оно может глючить на тех же ноутбуках. Кроме того на картах типа кушных вертекс арраи быстрее VBO.
с такой маааленькой поправкой - без переключения текстур, без освещения, без студиомоделей и вообще без эдиктов.
А как только ты всё это нарисуешь, у тебя всё вернется обратно на круги своя.
Ну это я просто для сравнения - 3000 и 280
Цитата:
вертекс арраи везде поддерживаются. VBO не везде, к тому же оно может глючить на тех же ноутбуках. Кроме того на картах типа кушных вертекс арраи быстрее VBO. [/B]