2013-12-05 2 views
0

Тесселяция местности: Я обрабатываю свою местность с клип-картами с усечками и тосселяционными шейдерами. Теперь, чтобы повысить производительность, я хочу использовать некоторые тесселяционные шейдеры более эффективным способом. Моя цель - добиться очень высокой частоты кадров (~ 100 FPS) с приличным визуальным качеством, поэтому я собираюсь объединить 3 фактора тесселяции, карту тесселяции, зависимость от зависимости (пиксели на краю) и тесселяцию силуэта.Оптимизация тесселяции [OpenGL]

Моя идея представляет собой взвешенное среднее из них:

tessfac = tesscoeff*(w1*tessmapfactor+w2*silhtessfactor+w3*ppetessfactor)/(w1+w2+w3); 

с 3-х факторов колеблется от 0 ... 1, а tesscoeff может быть равномерная тоже для регулировки уровней. У меня есть карта и факторы радиус края, но ...

Силуэты: Как найти силуэт пятна на сетке, описанной с помощью простого y(x,z) функции? Я использую vertex-texture-fetch, поэтому я знаю соседние вершины/нормали. Это проблема, если я использую квадратные пятна, а не треугольники, или это не затрудняет их поиск?

(отредактирован BACK-PATCH) Backpatch Culling: Другая проблема, я столкнулся это тыльный забой. Как я уже сказал, я использую квадратные пятна, поэтому нельзя лежать на самолете. С треугольниками я бы сравнил нормальное с глазом направление, но на квадроциклах я не могу или не знаю, как это сделать.

Occlusion Culling: Я рендеринга местности с геометрией клип-карты с алгоритмом:

foreach(LOD) 
    foreach(quarter) 
     foreach(quad in quarter) //I mean x+z+, x-z+, x-z- and x+z- by quarters 
      quad.clipFrustum(); 
      if(inFrustum) quad.render(); 
     endloop 
    endloop 
endloop 

У меня есть один единый буфер вершин для простого n*n четырехъядерных формы беспорядок. У меня есть 4 индексных буфера для этой сетки, по одному для каждого квадранта этого квадранта. Для LOD=0 я визуализую центр/нижний левый quad, а для других уровней я только визуализирую L-образный беспорядок с другими 3 (вверху, topleft, слева) квадранты, масштабируемые pow(2,LOD). Затем вся сетка масштабируется с постоянной (сеткой).

Поскольку вся эта сетка расположена на каждом кадре перед камерой, сетка всегда отображается квадрантом по квадранту с начала координат. Может быть, он может быть использован для отбраковки, например, early-z или окклюзия в шейдерном управляющем шейдере?

Я ищу некоторый указатель на них, потому что все, что я нашел, это некоторые документы NVIDIA/AMD без особого технического фона. http://www.geeks3d.com/20101201/amd-graphics-blog-tessellation-for-all/ ссылка на полный текст статьи сломана тоже ... (с этого поста: OpenGL Low-Level Performance Questions)

+0

Что касается спины - ** лицо ** отбраковка, вы примитивная сборка, связанная в этом приложении? Обратное отбрасывание - это, как правило, операция растеризации, но в прошлые годы примитивная настройка была настолько дорогой, что двигатели иногда отбирали треугольники на уровне вершин (вспомните Quake 3, он вычислит список треугольников, чтобы нарисовать на ЦП каждый кадр). Некоторые игры для PS3 все еще делают это, поскольку это простой способ удержать процессор CELL, занятый работой, чтобы уменьшить общую нагрузку на RSX, но большую часть времени, отбрасывая эти дни, заключается в уменьшении нагрузки на приложения, связанные с фрагментами. –

+0

Думаю, вам больше понравится отбраковка back-patch. Отбросьте целые патчи, прежде чем вы решите отказаться от отдельных примитивов, которые они генерируют. –

+0

Что я хочу сделать, это отбросить обратные пятна, установив их уровни тесселяции на 0. Не называется ли это отбрасыванием назад-патча? (до редактирования я написал «back-face», исправлено «back-patch») –

ответ

1

Вы можете отбраковать треугольник (3 балла), используя следующие,

float3 vEdge0 = patch[1].PosW - patch[0].PosW; 
float3 vEdge1 = patch[2].PosW - patch[0].PosW; 

float3 vFaceNormal0 = normalize(cross(vEdge1, vEdge0)); 
float2 vView0 = normalize(patch[0].PosW - gEyePosW); 

if (dot(vView0, vFaceNormal0) < -0.25f) 
{ 
    pt.EdgeTess[0] = 0.0f; 
    pt.EdgeTess[1] = 0.0f; 
    pt.EdgeTess[2] = 0.0f; 

    pt.InsideTess = 0.0f; 

    return pt; 
} 

Вы должны быть в состоянии вырезать патч, образуя 4 треугольника, например [\] (2 треугольника от верхней левой точки до нижней правой точки) и [/] (2 треугольника сверху справа налево слева) из 4-х угловых точек патча, и если все точки (vView, vFaceNormal) < -0.25f, довольно безопасно сказать, что патч обращен в сторону от глаз пользователя.Но это приближение средних (ваши 4 треугольника из угловых точек). В зависимости от вашего размера патча и количества сумасшедших вещей (гор и долин), которые вы совершаете в патче, это может не работать в любой ситуации, и это может быть причиной того, что в сети мало информации об этом. Вам просто нужно будет проверить и посмотреть.

Я скажу, что вы могли бы пойти еще дальше, если по какой-то причине вы видите, что это не работает во всех ваших ситуациях и абсолютно необходимо отбирать в шейдере корпуса, который вы могли бы передать в HeightMap как текстуру и образец еще больше треугольников (например, получить средние точки патча), чтобы [x] получить еще четыре треугольника, даже [*], чтобы получить еще 8 треугольников.

Более безопасный способ совершить одно и то же без огромного количества работы - отбросить кулак, пройти в плоскостях вашей ограничивающей камеры и проверить ограничительную рамку патча. Вот код шейдера;

float3 vMin = float3(patch[0].PosW.x, minY, patch[0].PosW.z); 
float3 vMax = float3(patch[3].PosW.x, maxY, patch[3].PosW.z); 

if (!IntersectsOrContainsBoundingBox(vMin.x, vMin.y, vMin.z, vMax.x, vMax.y, vMax.z)) 
{ 
    pt.EdgeTess[0] = 0.0f; 
    pt.EdgeTess[1] = 0.0f; 
    pt.EdgeTess[2] = 0.0f; 
    pt.EdgeTess[3] = 0.0f; 

    pt.InsideTess[0] = 0.0f; 
    pt.InsideTess[1] = 0.0f; 

    return pt; 
} 

bool IntersectsOrContainsBoundingBox(float minWidth, float minHeight, float minDepth, float maxWidth, float maxHeight, float maxDepth) 
{ 
// check box outside/inside of frustum 
for (int i = 0; i < 6; i++) 
{ 
    int output = 0; 
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0); 
    if (output == 8) 
    { 
     return false; 
    } 
} 

return true; 
} 
+0

Прошло уже два года, и я решил это, поэтому он решен к настоящему времени: D btw +1 –

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