2014-09-13 10 views
2

Я использую OpenGL через OpenTK на C# и пытаюсь загрузить текстуры из общих растровых изображений. Мой драйвер не поддерживает текстуры NPOT, поэтому я выделяю POT текстуру с GL.TexImage2D и заполняю ее своим растровым изображением через GL.TexSubImage2D. Однако у меня есть артефакты во время рисования этих текстов. Кажется, что он также рисует дополнительный пиксель в нижней и правой частях текстуры. Должен ли я просто вычесть пиксель из соотношения или что-то еще не так?Использование OpenGL GL.TexSubImage2D для текстур NPOT приводит к артефактам

Код для создания:

GL.BindTexture(TextureTarget.Texture2D, t.Name); 

GL.PixelStore(PixelStoreParameter.PackAlignment, 1); 
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); 
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, texture.W2, texture.H2, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); 
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, texture.DataSize.Width, texture.DataSize.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data); 

GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); 
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); 
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); 
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); 
GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D); 

GL.BindTexture(TextureTarget.Texture2D, 0); 

Код для рисования:

GL.BindTexture(TextureTarget.Texture2D, t.Name); 

float x1 = 0; 
float x2 = texture.WidthRatio; 
float y1 = 0; 
float y2 = texture.HeightRatio; 

float rx1 = rect.X; 
float rx2 = rect.X + rect.W; 
float ry1 = rect.Y; 
float ry2 = rect.Y + rect.H; 

GL.Begin(BeginMode.Quads); 

GL.TexCoord2(x1, y1); 
GL.Vertex3(rx1, ry1, rect.Z + CGraphics.ZOffset); 

GL.TexCoord2(x1, y2); 
GL.Vertex3(rx1, ry2, rect.Z + CGraphics.ZOffset); 

GL.TexCoord2(x2, y2); 
GL.Vertex3(rx2, ry2, rect.Z + CGraphics.ZOffset); 

GL.TexCoord2(x2, y1); 
GL.Vertex3(rx2, ry1, rect.Z + CGraphics.ZOffset); 

GL.End(); 

GL.Disable(EnableCap.Blend); 
GL.BindTexture(TextureTarget.Texture2D, 0); 

Где texture.WidhtRatio = DataSize.Width/W2;

ответ

1

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

  1. Filtering (что происходит между текселей)

    • Ближайшие
    • Linear

    Разница может быть видны на изображении ниже.

  2. Wrap режимы (что происходит после того, как границы текстуры)

    Примечание оберточная цвета, даже если координаты текстуры не снаружи -1 до 1 - - комбинация как линейной фильтрации, так и режима повторной упаковки.

Другая важная вещь, которая нуждается в произношении, - это образцы, расположенные посередине пикселей и текселей. Вот почему gl_FragCoord.xy всегда имеет долю .5 (пока вы не получите мульти/супер-выборку и т. Д.). Это можно увидеть на изображении ниже. Я подозреваю, что это проблема.Вы можете настроить координаты текстуры, чтобы пробовать вставку вашей текстуры, чтобы избежать интерполяции соседних пикселей (то есть x+0.5 - x+width-0.5).

enter image description here


мипмапов будет содержать цвет от большей площади, так просто изменяя координаты не будут работать. Чтобы воссоздать поведение GL_CLAMP_TO_EDGE, вам действительно нужно экструдировать границу суб изображения. Альтернативно, просто очистка текстуры перед загрузкой будет намного проще. Быстрый способ прикрепить текстуру к FBO и glClear:

glGenFramebuffers(1, &fbo); 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); 
glClear(GL_COLOR_BUFFER_BIT); 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 
//glDeleteFramebuffers(1, &fbo); 

Чтобы идти на шаг вперед и выталкивать текстуру, я бы загрузить вспомогательный образ, а затем сделать четверной над подизображений и желаемой границы , В шейдере фрагмента отбросьте пиксели внутри вспомогательного изображения и буквально вызовите coord = clamp(coord, imageMin, imageMax). Чтобы избежать двойной буферизации, read while drawing. Если у вас было несколько вспомогательных изображений, вы могли бы использовать z-буфер здесь и рисовать квадратные пирамиды вместо квадов, позволяя глубже работать как минимальное расстояние до любого суб-изображения (точно так же, как drawing voronoi cells with cones)

+0

+1 Действительно приятно объяснение. Однако проблема связана с картами mip для уменьшенного текстурного рисунка. Какие-нибудь решения здесь? – Flamefire

+0

@Flamefire Я думаю, это зависит от содержания текстуры. Сначала можно очистить его альфой или цвет фона (быстро с FBO + glClear). Если нет, то, как предлагает RetoKoradi, добавление границы может быть лучше. Если вы используете только первые несколько уровней mipmap, граница может быть небольшой. Вы также можете генерировать его в шейдере фрагментов, чтобы ускорить работу. – jozxyqk

+0

Не могли бы вы предоставить ссылку, как использовать FBO для достижения этой цели? – Flamefire

1

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

Предполагая, что вы хотите включить билинейную фильтрацию, вы можете дублировать последнюю строку и последний столбец текстуры текстурных данных. Другими словами, если ваша текстура NPOT равна 800x600, загрузите 801x601 пикселей с повторением последнего столбца/строки.

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

Редактировать: как рекомендовал Рето Коради, это будет работать только при использовании мипмапов. Если вы используете mipmaps, и особенно если вы используете анизотропную фильтрацию, вы должны заполнить всю пустую область последним столбцом/строкой.

+0

Я подумал об этом, когда впервые увидел этот вопрос. Я не думаю, что достаточно повторить один ряд/столбец. Это будет работать до тех пор, пока используется только самая низкая mipmap. Но для более высоких уровней mipmap будет использоваться больше неинициализированных данных текстуры. Я считаю, что вам нужно заполнить всю текстуру реплицированными данными, чтобы получить чистые значения выборки для всех мип-карт. –

+0

Вы правы, это было бы необходимо, если вы используете 'GL.GenerateMipmap()' и/или анизотропную фильтрацию. Я исправлю свой ответ. –

+0

Вы правы. Проблема возникает с мипмапами. Однако другие minFilters действительно плохие, поэтому мне действительно нужно дублировать последнюю строку/столбец по всей текстуре? Может быть немного медленным (по крайней мере для колос) ... – Flamefire

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

  • Нет связанных вопросов^_^