Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 24.01.2020, 11:20   #1
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию OpenGL проседает FPS при выборе объектов

Здравствуйте.
Написал программу с использованием OpenGL, в которой рендерятся кубы. Количество кубов составляет 256х256х16.
Теперь необходимо сделать выбор объектов. Чтобы когда камера смотрит на какую-то грань куба, эта грань подсвечивалась другим цветом (или текстурой - не важно).
Перечитав много информации на эту тему, до меня наконец дошло как это делается. Один из способов - это использование буфера выбора.
Смысл в том, что надо переключиться в режим GL_SELECT и нарисовать невидимые грани кубов (без текстуры и без цвета). Желательно рисовать только объекты близкие к камере, иначе FPS упадет до нуля. Потом переключиться обратно в режим GL_RENDER и нарисовать всё то же самое, но с текстурами или просто разными цветами.
Потом нужно проанализировать получившийся буфер выбора, найти ближайшую к камере грань куба и подсветить ее. Всё просто.
Но при такой операции сильно проседает FPS. Но проблема не именно в том, что он проседает. А в том, что если написать такую же программу на Java, то там FPS проседает не так сильно.
То есть, получается странная хрень. Один и тот же код, написанный на Java / C++ выдает разный FPS (при одинаковой позиции камеры).
На Java это ~80 FPS, на C++ ~60 FPS. Почему такая большая разница, да к тому же в пользу Java, а не наоборот? Причем, проседает именно на рисовании квадов в режиме GL_SELECT.
Если отключить выбор объектов, то на обоих языках FPS примерно одинаковый - ~120 FPS. Это значит, что проблема где-то в коде выбора.
код:
Код:
void ObjectSelector::RenderGhostCubeSide(Tesselator* t, int x, int y, int z, int side){
    float x0 = x * world->blockWidth;
    float y0 = y * world->blockHeight;
    float z0 = z * world->blockWidth;
    float x1;
    float y1;
    float z1;
    switch (side){
        case BLOCK_SIDE_FRONT:
            if (!world->IsBlockSolid(x, y, z + 1)) {
                x1 = x0 + world->blockWidth;
                y1 = y0 + world->blockHeight;
                z1 = z0 + world->blockWidth;
                t->AddVertexQuad(x0, y0, z1);
                t->AddVertexQuad(x1, y0, z1);
                t->AddVertexQuad(x1, y1, z1);
                t->AddVertexQuad(x0, y1, z1);
            }
            break;

        case BLOCK_SIDE_BACK:
            if (!world->IsBlockSolid(x, y, z - 1)) {
                x1 = x0 + world->blockWidth;
                y1 = y0 + world->blockHeight;
                t->AddVertexQuad(x0, y0, z0);
                t->AddVertexQuad(x1, y0, z0);
                t->AddVertexQuad(x1, y1, z0);
                t->AddVertexQuad(x0, y1, z0);
            }
            break;

        case BLOCK_SIDE_LEFT:
            if (!world->IsBlockSolid(x - 1, y, z)) {
                y1 = y0 + world->blockHeight;
                z1 = z0 + world->blockHeight;
                t->AddVertexQuad(x0, y0, z0);
                t->AddVertexQuad(x0, y0, z1);
                t->AddVertexQuad(x0, y1, z1);
                t->AddVertexQuad(x0, y1, z0);
            }
            break;

        case BLOCK_SIDE_RIGHT:
            if (!world->IsBlockSolid(x + 1, y, z)) {
                x1 = x0 + world->blockWidth;
                y1 = y0 + world->blockHeight;
                z1 = z0 + world->blockWidth;
                t->AddVertexQuad(x1, y0, z0);
                t->AddVertexQuad(x1, y0, z1);
                t->AddVertexQuad(x1, y1, z1);
                t->AddVertexQuad(x1, y1, z0);
            }
            break;

        case BLOCK_SIDE_TOP:
            if (!world->IsBlockSolid(x, y + 1, z)) {
                x1 = x0 + world->blockWidth;
                y1 = y0 + world->blockHeight;
                z1 = z0 + world->blockWidth;
                t->AddVertexQuad(x0, y1, z0);
                t->AddVertexQuad(x0, y1, z1);
                t->AddVertexQuad(x1, y1, z1);
                t->AddVertexQuad(x1, y1, z0);
            }
            break;

        case BLOCK_SIDE_BOTTOM:
            if (!world->IsBlockSolid(x, y - 1, z)) {
                x1 = x0 + world->blockWidth;
                z1 = z0 + world->blockWidth;
                t->AddVertexQuad(x0, y0, z0);
                t->AddVertexQuad(x0, y0, z1);
                t->AddVertexQuad(x1, y0, z1);
                t->AddVertexQuad(x1, y0, z0);
            }
            break;
    }
}

void ObjectSelector::RenderGhostCubeSides(float r){
    CollisionBox* box = player->collisionBox->Grow(r, r, r); //получаем область [x,y,z] радиусом R вокруг камеры (обычно = 3.0)
    int x0 = (int)box->x0;
    int x1 = (int)box->x1;
    int y0 = (int)box->y0;
    int y1 = (int)box->y1;
    int z0 = (int)box->z0;
    int z1 = (int)box->z1;
    delete box;
    float n = worldRenderer->worldObj->cubeSize / 2.0;
    glInitNames();
    for (int x = x0; x <= x1; x++) {
        for (int y = y0; y <= y1; y++) {
            for (int z = z0; z <= z1; z++){
                if (worldRenderer->worldObj->GetBlock(x, y, z) > 0 &&
                    frustumObj->CubeInFrustum(x + n, y + n, z + n, n)) {
                    int id = worldRenderer->worldObj->GetArrayId(x, y, z);
                    glPushName(id);
                    for (int i = 0; i < 6; i++) {
                        glPushName(i);
                        tesselator->ClearQuads();
                        RenderGhostCubeSide(tesselator, x, y, z, i); //тут просадка FPS
                        tesselator->FlushQuads();
                        glPopName();
                    }
                    glPopName();
                }
            }
        }
    }
}

int ObjectSelector::PickObject(float radius){ //это вызываем перед рендером сцены
    ZeroMemory(&selectBuffer, 200);
    glSelectBuffer(200, selectBuffer);
    glGetIntegerv(GL_VIEWPORT, viewportBuffer);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glRenderMode(GL_SELECT);
    gluPickMatrix((double)glScreenWidth / 2.0, (double)glScreenHeight / 2.0, 2.0, 2.0, viewportBuffer);
    gluPerspective(75.0, (double)glScreenWidth / (double)glScreenHeight, 0.05, 50.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRotatef(player->rotationRoll,  0.0, 0.0, 1.0);
    glRotatef(player->rotationPitch, 1.0, 0.0, 0.0);
    glRotatef(player->rotationYaw,   0.0, 1.0, 0.0);
    glTranslatef(-player->positionX, -player->positionY, -player->positionZ - 0.3);

    RenderGhostCubeSides(radius);
    
	int hits = glRenderMode(GL_RENDER);
	
	
	//bla-bla
	
	
	return hits;
}
Код тесселятора: https://pastebin.com/yX6qNqqv
BLACK_RAIN вне форума Ответить с цитированием
Старый 25.01.2020, 21:07   #2
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

в функции RenderGhostCubeSide тормозить нечему. Разве что внутри функций (я понятия не имею, что это за функции, и что в них)

IsBlockSolid
AddVertexQuad

Ещё, может, запускаешь дебаг, а не релиз?
Алексей1153 вне форума Ответить с цитированием
Старый 26.01.2020, 11:08   #3
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
IsBlockSolid
Достаёт число (0..255) из массива char*
Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
AddVertexQuad
Смотрите код тесселятора в конце поста. Там кода не много и всё довольно просто. Эта фунеция просто добавляет числа в массив, который потом передается в glDrawArrays().
Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
Ещё, может, запускаешь дебаг, а не релиз?
Это вообще на FPS не влияет. Даже если в консоли вручную компилировать. Выдает примерно 60 FPS.
Хотя я флаг оптимизации скорости не ставил (забыл). Сейчас попробую. P.S. Не помогло.
Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
в функции RenderGhostCubeSide тормозить нечему.
Я понимаю. Но куда-то ведь эти 20 FPS деваются.

Последний раз редактировалось BLACK_RAIN; 26.01.2020 в 11:58.
BLACK_RAIN вне форума Ответить с цитированием
Старый 27.01.2020, 10:22   #4
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

Цитата:
Сообщение от BLACK_RAIN Посмотреть сообщение
Но куда-то ведь эти 20 FPS деваются.
упрощай (облегчай) сцену , проверь, поднимется ли при этом fps. Если от количества графики скорость не зависит, может где-то какая-то хитрая настройка, ограничивающая скорость принудительно. Тогда можно не обращать внимания, 60 кадров - этого достаточно для глаз
Алексей1153 вне форума Ответить с цитированием
Старый 27.01.2020, 16:13   #5
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
упрощай (облегчай) сцену , проверь, поднимется ли при этом fps.
Это и так почти тестовый проект. Там просто массив кубов с текстурой рендерится. Там упрощать нечего. Если отключить выбор объектов, то выдаёт 120 FPS на обоих языках.
Может в тектуре дело? Я не уверен, правильно ли я ее загружаю в С++
но ведь без выбора объектов FPS одинаковый.

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
может где-то какая-то хитрая настройка, ограничивающая скорость принудительно
это вы о чём?

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
60 кадров - этого достаточно для глаз
для глаз-то и 40 достаточно. Но если вводить в сцену дополнительные вычисления, то 20 FPS лишними быть не могут.

Последний раз редактировалось BLACK_RAIN; 27.01.2020 в 16:20.
BLACK_RAIN вне форума Ответить с цитированием
Старый 28.01.2020, 08:27   #6
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Избавляйтесь от циклов. В RenderGhostCubeSides дичь какая то. Есть же glList. Создайте списки рендеринга и потом только их и вызывайте. Удивительно что всего 20 фпс потеряли..
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.
WorldMaster вне форума Ответить с цитированием
Старый 28.01.2020, 11:44   #7
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию

Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Избавляйтесь от циклов. В RenderGhostCubeSides дичь какая то.
Почему дичь? А как тогда перебирать кубы вокруг камеры, если не циклом?
Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Есть же glList. Создайте списки рендеринга и потом только их и вызывайте.
А если камера постоянно движется? Какой тогда смысл в листах?
Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Удивительно что всего 20 фпс потеряли..
Но на Java тот же самый код эти 20 кадров не теряет. А если отключить выбор объектов, то FPS одинаковый.
Тогда не пойму, зачем что-то менять. Ведь тогда в сравении не будет смысла.
BLACK_RAIN вне форума Ответить с цитированием
Старый 28.01.2020, 12:02   #8
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Цитата:
Сообщение от BLACK_RAIN Посмотреть сообщение
А если камера постоянно движется? Какой тогда смысл в листах?
И что? Видимо разработчики сильно ошиблись когда придумали этот механизм. Движение камеры в 3д это ведь такая редкость.
У меня пару проектов в прошлом с листами сделано где по 500 000 точек рендерится и фпс стабильный.

Цитата:
Сообщение от BLACK_RAIN Посмотреть сообщение
Тогда не пойму, зачем что-то менять.
Действительно.

Тогда непонятны ваши жалобы. Выбор же очевиден - возьмите жабу и пишите на ней.
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.

Последний раз редактировалось WorldMaster; 28.01.2020 в 12:05.
WorldMaster вне форума Ответить с цитированием
Старый 28.01.2020, 12:09   #9
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

BLACK_RAIN,

Цитата:
The name stack is always empty while the render mode is not GL_SELECT. Calls to glPushName or glPopName while the render mode is not GL_SELECT are ignored.
а точно ли там тебе нужны вызовы
Код:
                    worldRenderer->worldObj->GetArrayId
                    glPushName(id);
                        glPushName(i);
                        glPopName();
                    glPopName();
?
Алексей1153 вне форума Ответить с цитированием
Старый 28.01.2020, 13:45   #10
BLACK_RAIN
Форумчанин
 
Регистрация: 13.02.2012
Сообщений: 867
По умолчанию

Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Тогда непонятны ваши жалобы.
покажите, где именно я жаловался.
А если менять код, как тогда можно сравнивать FPS?
Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
а точно ли там тебе нужны вызовы
Если их не вызывать, тогда в буфер выбора имена не добавляются. К сожалению.

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
The name stack is always empty while the render mode is not GL_SELECT. Calls to glPushName or glPopName while the render mode is not GL_SELECT are ignored.
Я же предварительно переключаюсь в режим GL_SELECT. Иначе, как бы тогда выбор объектов вообще работал?

Последний раз редактировалось BLACK_RAIN; 28.01.2020 в 14:28.
BLACK_RAIN вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Перемещение объектов в opengl Chester751 Общие вопросы Delphi 1 20.09.2013 20:49
Пересечение объектов OpenGL saggy Мультимедиа в Delphi 1 02.07.2010 17:02
OpenGL. Независимое движение объектов. Krechet Мультимедиа в Delphi 7 24.04.2010 21:37
Проблема при использовании прозрачности объектов в OpenGL Gwaeron Помощь студентам 0 22.04.2010 11:18
динамическое создание объектов OpenGl Seran4ek Помощь студентам 2 26.11.2009 17:04