2013-10-26 4 views
9

Когда его переводится в интегральное значение (1,2,3 и т. Д.), Между плитками нет черных линий, это выглядит нормально. Но когда он переводится на неинтегральную (1.1, 1.5, 1.67), между каждой плиткой есть маленькие черноватые линии (я представляю, что это связано с рендерингом субпикселя, правильно?) ... и это выглядит не очень красиво = Popengl, черные линии между плитами

Итак ... что мне делать?

Это мой образ заряжания код, кстати:

bool Image::load_opengl() { 
    this->id = 0; 

    glGenTextures(1, &this->id); 

    this->bind(); 

    // Parameters... TODO: Should we change this? 
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, this->size.x, this->size.y, 
    0, GL_BGRA, GL_UNSIGNED_BYTE, (void*) FreeImage_GetBits(this->data)); 

    this->unbind(); 

    return true; 
} 

Я также попытался с помощью:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

и:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

Вот мое изображение код чертежа:

void Image::draw(Pos pos, CROP crop, SCALE scale) { 
    if (!this->loaded || this->id == 0) { 
     return; 
    } 

    // Start position & size 
    Pos s_p; 
    Pos s_s; 

    // End size 
    Pos e_s; 

    if (crop.active) { 
     s_p = crop.pos/this->size; 
     s_s = crop.size/this->size; 
     //debug("%f %f", s_s.x, s_s.y); 
     s_s = s_s + s_p; 
     s_s.clamp(1); 
     //debug("%f %f", s_s.x, s_s.y); 
    } else { 
     s_s = 1; 
    } 

    if (scale.active) { 
     e_s = scale.size; 
    } else if (crop.active) { 
     e_s = crop.size; 
    } else { 
     e_s = this->size; 
    } 

    // FIXME: Is this okay? 
    s_p.y = 1 - s_p.y; 
    s_s.y = 1 - s_s.y; 

    // TODO: Make this use VAO/VBO's!! 
    glPushMatrix(); 

     glTranslate(pos.x, pos.y, 0); 

     this->bind(); 

     glBegin(GL_QUADS); 

      glTexCoord2(s_p.x, s_p.y); 
      glVertex2(0, 0); 

      glTexCoord2(s_s.x, s_p.y); 
      glVertex2(e_s.x, 0); 

      glTexCoord2(s_s.x, s_s.y); 
      glVertex2(e_s.x, e_s.y); 

      glTexCoord2(s_p.x, s_s.y); 
      glVertex2(0, e_s.y); 

     glEnd(); 

     this->unbind(); 

    glPopMatrix(); 
} 

OpenGL инициализации код:

void game__gl_init() { 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluOrtho2D(0.0, config.window.size.x, config.window.size.y, 0.0); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glDisable(GL_DEPTH_TEST); 
    glEnable(GL_BLEND); 
    glEnable(GL_TEXTURE_2D); 
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
} 

Скриншоты выпуска:

Screenshot 1 Screenshot 2

+0

Вы немного расплывчаты, не могли бы вы уточнить, что вы делаете? Вы рисуете набор смежных плиток и переводете их на сумму? Или вы рисуете повторяющиеся текстуры? Возможно, это будет скриншот, если это сложно. –

+0

@FullFrontalNudity Правильно, я рисую много плиток, все рядом друг с другом (конец одного - это начало другого). В нем используется спрайт, содержащий все плитки. Каждая плитка, когда она нарисована, переводится в правильное положение, затем нарисована на 0, 0. – MiJyn

+0

@FullFrontalNudity Там, я добавил код рисунка изображения в сообщение :) – MiJyn

ответ

18

Проблема с использованием текстуры атласы (спрайт листов) и прилегающих к текселей протечки должен делать с тем, как линейная фильтрация текстур.

Для любой точки текстуры, которая не выбрана точно в центре текста, линейная выборка будет отображать 4 соседних текста и вычислять значение в месте, которое вы задали как взвешенное (исходя из расстояния от точки выборки) среднее из всех 4 образцов.

Вот хорошая визуализация проблемы:

image0

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

Обратите внимание, что при использовании анизотропной фильтрации вам может потребоваться увеличить ширину границы. Это связано с тем, что анизотропная фильтрация увеличит размер окрестности образца под крайними углами.


Чтобы проиллюстрировать, что я имею в виду, используя границу вокруг края каждой текстуры, рассмотрите различные режимы обертывания, доступные в OpenGL. Обратите особое внимание на CLAMP TO EDGE.

image1

Несмотря на наличие режима под названием «Зажим для Border», что на самом деле не то, что нас интересует. Этот режим позволяет определить один цвет, используемый в качестве границы вокруг вашей текстуры для любой текстуры которые выходят за пределы нормализованного диапазона [0.0-1.0].

Мы хотим, чтобы репликация поведения CLAMP_TO_EDGE, где любая координата текстуры вне соответствующего диапазона для (суб) текстуры получает значение последнего центра текселя в том направлении, в котором оно было за пределами. Поскольку вы имеют почти полный контроль над координатами текстуры в атласной системе, единственный сценарий, в котором (эффективные) координаты текстуры могут ссылаться на местоположение за пределами вашей текстуры, во время взвешенного среднего этапа фильтрации текстур.

Мы знаем, что GL_LINEAR будет отображать 4 ближайших соседей, как показано на диаграмме выше, поэтому нам нужна только 1-тексельная граница. Если вы используете анизотропную фильтрацию, вам может понадобиться более широкая граница текселя, поскольку при определенных условиях она увеличивает размер окрестности образца.

Вот пример текстуры, которая более четко иллюстрирует границу, хотя для ваших целей вы можете сделать границу 1 тексель или 2 текселя в ширину.

image2

(Примечание: Граница я имею в виду не черный вокруг всех четырех краев изображения, но область, где рисунок шахматной доски перестает регулярно повторять)

В случае, если вам интересно , вот почему я продолжаю поднимать анизотропную фильтрацию. Он изменяет форму образца окрестностей, основанную на угле и может привести к более чем 4 текселей, которые будут использоваться для фильтрации:

image3

Чем больше степени анизотропии вы используете, тем более вероятно, вам придется иметь дело с образцами, содержащими более 4 текселей. Для большинства анизотропных фильтрующих ситуаций должна быть достаточной граница 2 текселя.


И последнее, но не в последнюю очередь, вот как упакованные текстуры атлас будет построен, что бы повторить GL_CLAMP_TO_EDGE поведение в присутствии GL_LINEAR текстуры фильтр:

(Subtract 1 из X и Y в черные координаты, я не доказательство читать изображения перед публикацией.)

Благодаря хранению границы, хранение 4 256x256 текстуры в атласе требует текстуры с dimensi 516x516. Границы имеют цветовую маркировку на основе, как вы бы заполнить их с данными TEXEL при создании атласа:

  • Красный = Заменить тексела непосредственно под
  • Желтый = Заменить тексела непосредственно над
  • Зеленый = Заменить тексела непосредственно слева
  • Синих = Заменить тексел непосредственно справа

Эффективны в этом упакованы, например, каждой текстуре в атласе использует 258x258 области атласа, но вы Wi Создадим координаты текстуры, которые отображаются в видимой области 256x256. Приграничные тексели используются только когда текстурная фильтрация выполняется по краям текстур в атласе, а способ их создания имитирует поведение GL_CLAMP_TO_EDGE.

В случае, если вам интересно, вы можете реализовать другие типы режимов обертывания, используя аналогичный подход - GL_REPEAT может быть реализован путем обмена текстурами левого/правого и верхнего/нижнего границ текстурного атласа и немного умного текстурная координатная математика в шейдере. Это немного сложнее, поэтому не беспокойтесь об этом пока. Так как вы только дело с спрайтов листов ограничивать себя GL_CLAMP_TO_EDGE :)

+0

Спасибо за потрясающий ответ (вам не нужно было его копировать из gamedev хотя =)), но это похоже на большую работу ... I просто решил взять легкий маршрут и разделить spritesheet в отдельные файлы и использовать это (у моего spritesheet только 2 плитки, которые я использую anyways XD). – MiJyn

+0

@MiJyn: Это может быть много работы, но если вы используете инструмент, специально предназначенный для построения спрайтов, многие из них имеют встроенную функцию. Фактическая реализация этой функции обычно не обсуждается в этой детали;) Например, в [TexturePacker] (http://www.codeandweb.com/texturepacker/documentation) это называется ** Shape Padding ** , –

+0

Хотя, подумайте, что описание в документации неверно. Последнее, что вы хотите, если ваш спрайт непрозрачен от края до края, является прозрачной рамкой, потому что тогда вы заканчиваете артефактами, подобными тем, которые приведены в вашем примере ... –

2

У меня была такая же проблема, как показано на рисунке:

problem

Идея заключается в том, чтобы сжать изображения в атласе на один пиксель, и замените пиксели цветом, смежным с 1px «границей». Как только это будет сделано, отрегулируйте УФ-коррекцию для учета границы 1px. Другими словами, фактические координаты текстуры будет (для верхнего левого угла в нижний правый угол): start_x + 1, start_y + 1, end_x - 1, end_y -1

До:

bad atlas

После:

good atlas

После применения, это результат:

fixed

+0

Если UV-координаты отображаются, учитывая маржу 1px, есть ли причина, чтобы граница дублировала соседние пиксели? – MiJyn

+0

Хорошо, спасибо за редактирование моего ответа и публикации изображений на странице. Но посмотрите, затем плитки выглядят искаженными [link] (https://yadi.sk/i/it5hSx1XiXRid), нормальный - [link] (https://yadi.sk/i/RPuF4DxAiXRro). Я думаю, это происходит потому, что оригинальное изображение атласа потеряло эти пиксели границы, но на самом деле оно должно быть собрано соседями, как это первоначально упоминалось Андоном М. Колеманом –

0

Еще одна проблема, если у вас есть прозрачный пиксель в вашей текстуры:

Когда OpenGL использовать линейный фильтр для масштабирования текстуры, то смешать некоторые пиксели с прозрачным пикселем, но в большинстве случаев, прозрачный цвет пикселя белый, поэтому результат смешанного пикселя не имеет ожидаемого цвета. Чтобы исправить это, решение состоит в создании предварительно умноженной альфы. Я создал сценарий для достижения этой цели на Gimp:

(define (precompute-alpha img color) 

    (define w (car (gimp-image-width img))) 
    (define h (car (gimp-image-height img))) 

    (define img-layer (car (gimp-image-get-active-layer img))) 

    (define img-mask (car (gimp-layer-create-mask img-layer ADD-ALPHA-TRANSFER-MASK))) 
    (gimp-layer-add-mask img-layer img-mask) 
    (define alpha-layer (car (gimp-layer-new img w h RGBA-IMAGE "alpha" 100 NORMAL-MODE))) 
    (gimp-image-insert-layer img alpha-layer 0 -1) 
    (gimp-edit-copy img-mask) 
    (define floating-sel (car (gimp-edit-paste alpha-layer TRUE))) 
    (gimp-floating-sel-anchor floating-sel) 

    (define bg-layer (car (gimp-layer-new img w h RGBA-IMAGE "bg" 100 NORMAL-MODE))) 
    (gimp-image-insert-layer img bg-layer 0 2) 
    (gimp-context-set-background color) 
    (gimp-drawable-fill bg-layer BACKGROUND-FILL) 

    (set! bg-layer (car (gimp-image-merge-down img img-layer 0))) 
    (define bg-mask (car (gimp-layer-create-mask bg-layer ADD-WHITE-MASK))) 
    (gimp-layer-add-mask bg-layer bg-mask) 

    (gimp-edit-copy alpha-layer) 
    (set! floating-sel (car (gimp-edit-paste bg-mask TRUE))) 
    (gimp-floating-sel-anchor floating-sel) 

    (gimp-image-remove-layer img alpha-layer) 
) 

(script-fu-register "precompute-alpha" 
    "Precompute Alpha" 
    "Automatically precompute alpha" 
    "Thomas Arbona" 
    "2017" 
    "2017" 
    "*" 
    SF-IMAGE "Image"   0 
    SF-COLOR "Alpha Color" '(0, 0, 0) 
) 

(script-fu-menu-register "precompute-alpha" "<Image>/Alpha") 

Просто откройте изображение в Gimp, откройте Альфа> Альфа предвычисления и выбрать цвет, чтобы предварительно вычислить альфа на изображении с этим цвет.