OpenGLES 2.0: визуальные артефакты 3D-тайлов

Мне ужасно трудно найти способ лучше обрабатывать швы между 3D-мозаичными объектами в моем игровом движке. Вы видите их только тогда, когда камера наклонена под достаточно большим углом, вот так ... Я не верю, что это проблема текстуры или проблема рендеринга текстуры (но я могу ошибаться).

Ниже приведены два снимка экрана: первый демонстрирует проблему, а второй — UV-обертку, которую я использую для тайлов в Blender. Я оставляю место в UV для перекрытия, так что, если текстуру нужно перерисовать во время небольших мип-карт, я все еще должен быть хорош. Я загружаю текстуры со следующими параметрами текстуры:

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

Мне кажется, что стороны 3D-тайлов слегка прорисовываются, и вы особенно замечаете артефакт из-за угла освещения (направленного), который применяется с этого угла.

Есть ли какие-нибудь приемы или вещи, которые я могу проверить, чтобы устранить этот эффект? Я визуализирую в «слоях», но внутри этих слоев в зависимости от расстояния до камеры (сначала самые дальние). Все эти объекты находятся в одном слое. Благодарим за любую идею!

Если это полезно, это проект для iPhone/iPad с использованием OpenGLES2.0. Я буду рад предоставить любые фрагменты кода — просто дайте мне знать, с чего лучше всего начать.

Скриншот из движка, демонстрирующий швы между плитками под малыми углами

UV из Blender

ОБНОВЛЕНИЕ С ПОМОЩЬЮ ВЕРШИННЫХ/ПИКСЕЛЬНЫХ ШЕЙДЕРОВ И ВЕРШИН МОДЕЛИ

В настоящее время я использую формат PowerVR POD для хранения данных модели, экспортированных из Blender (через Collada, а затем конвертер Collada2Pod от PowerVR). Вот координаты вершины GL_SHORT (пространство модели):

64 -64 32
64 64 32
-64 64 32
-64 -64 32
64 -64 -32
-64 -64 -32
-64 64 -32
64 64 -32
64 -64 32
64 -64 -32
64 64 -32
64 64 32
64 64 32
64 64 -32
-64 64 -32
-64 64 32
-64 64 32
-64 64 -32
-64 -64 -32
-64 -64 32
64 -64 -32
64 -64 32
-64 -64 32
-64 -64 -32

Так что все должно быть идеально гладко, я ожидаю. Вот шейдеры:

attribute highp vec3  inVertex; 
attribute highp vec3  inNormal;
attribute highp vec2  inTexCoord;

uniform highp mat4  ProjectionMatrix;
uniform highp mat4  ModelviewMatrix;
uniform highp mat3  ModelviewITMatrix;
uniform highp vec3  LightColor;
uniform highp vec3  LightPosition1;
uniform highp float LightStrength1;
uniform highp float LightStrength2;
uniform highp vec3  LightPosition2;
uniform highp float Shininess;

varying mediump vec2  TexCoord;
varying lowp    vec3  DiffuseLight;
varying lowp    vec3  SpecularLight;

void main()
{
    // transform normal to eye space
    highp vec3 normal = normalize(ModelviewITMatrix * inNormal);

    // transform vertex position to eye space
    highp vec3 ecPosition = vec3(ModelviewMatrix * vec4(inVertex, 1.0));

    // initalize light intensity varyings
    DiffuseLight = vec3(0.0);
    SpecularLight = vec3(0.0);

    // Run the directional light
    PointLight(true, normal, LightPosition1, ecPosition, LightStrength1);
    PointLight(true, normal, LightPosition2, ecPosition, LightStrength2);

    // Transform position
    gl_Position = ProjectionMatrix * ModelviewMatrix * vec4(inVertex, 1.0);

    // Pass through texcoords and filter
    TexCoord = inTexCoord;
}      

person David    schedule 29.08.2011    source источник
comment
Может быть, проблема с точностью вершин в вершинном шейдере?   -  person Johnmph    schedule 30.08.2011
comment
Возможно... Я проверю и свяжусь с вами. Я думаю, что использую обозначение highp... Я сохраняю фактические данные вершины в GL_SHORT для упакованных атрибутов. Может ли это быть причиной проблемы? Я думаю, что у меня была эта проблема до переключения с GL_FLOAT на GL_SHORT.   -  person David    schedule 30.08.2011
comment
Джон, не мог бы ты взглянуть на вершинный шейдер? Я использую высокий vec3 для своего inVertex и, глядя на GL_SHORT, которые я получаю из файла модели для этого 3D-объекта, я не вижу, где могут возникнуть какие-либо ошибки точности. Я пропустил что-то очевидное, может быть?   -  person David    schedule 30.08.2011
comment
Это выглядит правильно, проверьте ответ ниже, я также думаю, что это потому, что результат вычисления усекается из-за конечной точности переменных.   -  person Johnmph    schedule 01.09.2011


Ответы (2)


Я не знаю, как нарисованы ваши коробки, но я думаю, что проблема в этом. При вычислении вершин для каждого поля, я думаю, вы делаете что-то вроде этого (псевдокод)

int i,j,k;
float widht

for i,j,k in dims: 
  upper_left = (i,j,k)*width;
  upper_right = (upper_left.x+width,upper_left.y,upper_left.z);
  lower_left = (upper_left.x, upper_left.y+width,upper_left.z);
  lower_right = (upper_left.x+width,upper_left.y+width,upper_left.z);

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

вместо этого вы должны сделать что-то вроде этого

for i,j,k: 
  upper_left = (i,j,k)*width;
  upper_right = (i+1,j,k)*width;
  lower_left = (i,j+1,k)*width;
  lower_right = (i+1,j+1,k)*width;

Это гарантирует, что углы будут использовать одни и те же координаты.

ИЗМЕНИТЬ

Это все еще проблема точности. Насколько я понимаю, вы выполняете вызов отрисовки для каждого блока, где единственное, что меняется в каждом блоке, это ModelviewMatrix. Это означает, что вы ожидаете, что эта строка

position = ProjectionMatrix * ModelviewMatrix * vec4 (inVertex, 1.0);

даст одно и то же значение для двух разных значений inVertex и ModelviewMatrix, что неверно.

Чтобы решить эту проблему, вы можете выполнить «поддельное» создание экземпляров (поскольку ES не поддерживает создание экземпляров), сохранив значения для каждого экземпляра в униформе и вычислив значения для каждого атрибута из индекса, заданного в атрибуте.

Редактировать 2:

Хорошо, пожалуйста, пока не думайте о "фальшивом" экземпляре. Теперь, пожалуйста, просто убедитесь, что координаты совпадают. Таким образом, вместо того, чтобы предоставлять координаты только для одного блока, укажите их для всех блоков и используйте только один ModelViewMatrix. Это, вероятно, также будет быстрее.

person Arne Bergene Fossaa    schedule 30.08.2011
comment
Арне, спасибо за быстрый ответ! В настоящее время я использую GL_SHORTS для хранения вершин модели в формате файла PowerVR .POD. Я обновил исходный пост, чтобы показать вершины, используемые в модели - как вы можете видеть, по крайней мере, в этом случае я не думаю, что это проблема точности. Я также опубликую шейдер, который я использую, на случай, если это может вызвать проблему... - person David; 30.08.2011
comment
Я думаю, что понимаю, что вы предлагаете... ModelviewMatrix относится к положению каждой модели по отношению к камере... поэтому, если у вас есть два объекта рядом друг с другом, разделяющие верхнюю левую и верхнюю правую вершины (слева от obj1, справа от obj2), эта вершина находится в тех же мировых координатах, но ее матрица представления модели немного отличается, создавая этот артефакт. Это правильно? Кажется, я понимаю, что такое создание экземпляров (многократное отображение одного объекта с уникальными атрибутами?), но не знаю, как мне это осуществить. Не могли бы вы предоставить немного больше деталей? Кажется, у меня почти получилось! - person David; 31.08.2011
comment
Что ж, OpenGL ES не поддерживает создание экземпляров, поэтому простое решение — создать все координаты на устройстве. То, что я упомянул, является уловкой, позволяющей обойти тот факт, что GLES не поддерживает создание экземпляров. Это совершенно особая вещь, вы сохраняете все данные, которые относятся к экземпляру (позиция модели в мире), и данные, которые относятся к вершине (относительные позиции) в униформах, и используете идентификатор для каждого вершина, чтобы указать, какие переменные вершины и экземпляра использовать. Вероятно, в вашем случае сейчас на это не стоит смотреть, так как это, вероятно, только усложнит ваш код. - person Arne Bergene Fossaa; 31.08.2011
comment
Арне, теперь это имеет гораздо больше смысла... Наверное, прошлой ночью я был в тумане после долгого дня кодирования! У меня впереди напряженный день, но я поиграю с ним сегодня вечером и вернусь с вами. Большое спасибо, что нашли время, чтобы предоставить такую ​​​​полезную информацию! - person David; 31.08.2011
comment
Просто обновление, я думаю, что это решение, но я все еще играю с ним. Увязли в некоторых других проблемах, которые возникли при обновлении до новой бета-версии Xcode — разберитесь! Я скоро закончу и вернусь к вам... еще раз спасибо! - person David; 01.09.2011
comment
Оказывается, исправлением для меня было увеличение точности буфера глубины. Проблема, по-видимому, не в том, что вершины не выстраиваются должным образом, а в том, что они выстраиваются в одном и том же месте, поэтому многоугольники между вершинами находятся точно друг над другом. Чем дальше камера, тем больше z-боев вы видите. Я переместил ближний клип камеры с 1.0f на 25.0f, который хорошо работает в игре и кардинально решил проблему. - person David; 02.09.2011
comment
Этим вечером я провел много времени, пытаясь понять, что вы имели в виду, используя одну матрицу ModelView... моя матрица ModelView хранит: 1) вращение объекта, 2) масштаб, 3) перевод (положение в мире) ( это вся матрица мира), но и информация о камере (матрица вида). Как я могу использовать один для рендеринга всех моих блоков, когда (по крайней мере) все позиции в мире уникальны? Структура inVertex просто содержит вершины модели (в координатах модели). В любом случае я все еще могу попытаться собрать много плиток для повышения производительности. Хотя я неправильно понимаю? Спасибо! - person David; 02.09.2011

Попробуйте эти

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
person Lijiayu    schedule 31.08.2011
comment
Боюсь, эти настройки фильтра не помогли - все те же визуальные артефакты на нижних углах. Но спасибо, отличная идея! - person David; 02.09.2011