Войти
ПрограммированиеФорум2D графика и изометрия

Текстурированный фон OpenGL

#0
22:14, 28 июля 2013

Доброго времени суток. Изучаю OpenGL, пока что сижу на OpenTK + C# WinForms.
Затекстурировал нужную мне область большой картинкой, реализовал скроллинг, но почему-то возникают непонятные артефакты текстуры фона возле границ окна, похоже на мерцание/z-fighting, хотя, неясно откуда.

Параметры:

Param.XSize = glControl.Width;
Param.YSize = glControl.Height;
GL.Viewport(0, 0, Param.XSize, Param.YSize);
GL.Disable(EnableCap.DepthTest);
GL.DepthMask(false);
GL.Enable(EnableCap.Blend);
GL.Disable(EnableCap.CullFace);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.ClearColor(1, 1, 1, 0);э

Подгрузка текстуры:

int id = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, id);

Bitmap Bmp = new Bitmap(filename);
BitmapData bmp_data = Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmp_data.Scan0);

Bmp.UnlockBits(bmp_data);

GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);

Отрисовка:

GL.Enable(EnableCap.Texture2D);
             
GL.BindTexture(TextureTarget.Texture2D, 1); //Фон

GL.Begin(BeginMode.Quads);
GL.TexCoord2(0, 0);
GL.Vertex2(0, 0);
GL.TexCoord2(1, 0);
GL.Vertex2(Bmp.Width, 0);
GL.TexCoord2(1, 1);
GL.Vertex2(Bmp.Width, Bmp.Height);
GL.TexCoord2(0, 1);
GL.Vertex2(0, Bmp.Height);
GL.End();

GL.PopMatrix();

GL.BindTexture(TextureTarget.Texture2D, 2); //По аналогии - другие нужные текстуры, также глитчат на проблемных участках фона

На скриншот артефакт выловить очень сложно, но разок удалось (обвел эллипсами артефакт и что-то похожее на z-fighting сплошной GL_LINE в его зоне):

Скриншот | Текстурированный фон OpenGL

Буду признателен за любую помощь.


#1
0:35, 29 июля 2013

Избавился от всех плавающих запятых, но проблема не исчезла. Что я делаю не так?
Сильно уменьшил координаты вершин текстуры, артефакт исчез:

GL.Begin(BeginMode.Quads);
GL.TexCoord2(0, 0);
GL.Vertex2(0, 0);
GL.TexCoord2(1, 0);
GL.Vertex2(1600, 0);
GL.TexCoord2(1, 1);
GL.Vertex2(1600, 1000);
GL.TexCoord2(0, 1);
GL.Vertex2(0, 1000);
GL.End();

Оригинальный размер 2400*1350, в чем может быть проблема?

#2
13:06, 29 июля 2013

Наверное, дело в точности float.

Сделай статичный квад на весь экран и скроллинг текстурными координатами.

#3
18:41, 29 июля 2013

Скроллинг делаю с помощью glTranslate. Избавился от float-ов, пробовал копать в сторону z-fighting, увы, безрезультатно.

#4
19:17, 29 июля 2013

DummyUA
> Избавился от float-ов
Где избавился? :)

#5
19:58, 29 июля 2013

Привел все вертексы рисуемого участка glTranslate к целочисленному значению. Если убрать скроллинг, то белого артефакта не наблюдается, но возле краев экрана все текстуры/линии над фоном очень сильно мерцают

Еще один сркин артефакта:
sshot-1153 | Текстурированный фон OpenGL

#6
21:05, 29 июля 2013

Не приводится к целочисленному. Он их во флоаты конвертирует.

#7
1:14, 30 июля 2013

Если так, то что надо предпринять?

#8
1:19, 30 июля 2013

> Сделай статичный квад на весь экран и скроллинг текстурными координатами.

#9
1:36, 30 июля 2013

Chipmunk, может, я чего не понял, но квад у меня и так статичен по размеру экрана, а транслейт происходит по интовым значением. Без скроллинга текстуры над фоном мерцают на некоторых участках.

#10
2:10, 30 июля 2013

MDS, скроллинг:

            if (HullOwner.Center.X >= MainForm.Param.XSize / 2 && HullOwner.Center.Y >= MainForm.Param.YSize / 2)
            {
                GL.Translate(Math.Round(-HullOwner.Center.X + MainForm.Param.XSize / 2), Math.Round(-HullOwner.Center.Y + MainForm.Param.YSize / 2), 0);
            }
            else if (HullOwner.Center.X >= MainForm.Param.XSize / 2)
            {
                GL.Translate(Math.Round(-HullOwner.Center.X + MainForm.Param.XSize / 2), 0, 0);
            }
            else if (HullOwner.Center.Y >= MainForm.Param.YSize / 2)
            {
                GL.Translate(0, Math.Round(-HullOwner.Center.Y + MainForm.Param.YSize / 2), 0);
            }

отрисовка фона:

            GL.Enable(EnableCap.Texture2D);
             
            GL.BindTexture(TextureTarget.Texture2D, 1);

            int ver = 900*1000;

            GL.Begin(BeginMode.Quads);
            GL.TexCoord3(0, 0, -1f);
            GL.Vertex3(0, 0, -1f);
            GL.TexCoord3(1000, 0, -1f);
            GL.Vertex3(ver, 0, -1f);
            GL.TexCoord3(1000, 1000, -1f);
            GL.Vertex3(ver, ver, -1f);
            GL.TexCoord3(0, 1000, -1f);
            GL.Vertex3(0, ver, -1f);
            GL.End();

Отрисовка поверх фона:

            GL.BindTexture(TextureTarget.Texture2D, 2);

            PointF planeTexturePosition1 = new PointF(HullOwner.Center.X - Bmp.Width/2, HullOwner.Center.Y - Bmp.Height/2);
            PointF planeTexturePosition2 = new PointF(HullOwner.Center.X + Bmp.Width/2, HullOwner.Center.Y - Bmp.Height/2);
            PointF planeTexturePosition3 = new PointF(HullOwner.Center.X + Bmp.Width/2, HullOwner.Center.Y + Bmp.Height/2);
            PointF planeTexturePosition4 = new PointF(HullOwner.Center.X - Bmp.Width/2, HullOwner.Center.Y + Bmp.Height/2);

            PointF planeTexturePositionRotated1 = Geometry.RotatePoint(planeTexturePosition1, HullOwner.Center, Degree);
            PointF planeTexturePositionRotated2 = Geometry.RotatePoint(planeTexturePosition2, HullOwner.Center, Degree);
            PointF planeTexturePositionRotated3 = Geometry.RotatePoint(planeTexturePosition3, HullOwner.Center, Degree);
            PointF planeTexturePositionRotated4 = Geometry.RotatePoint(planeTexturePosition4, HullOwner.Center, Degree);

            GL.Begin(BeginMode.Quads);
            GL.TexCoord3(0, 0, 1f);
            GL.Vertex3(planeTexturePositionRotated1.X, planeTexturePositionRotated1.Y, 1f);
            GL.TexCoord3(1, 0, 1f);
            GL.Vertex3(planeTexturePositionRotated2.X, planeTexturePositionRotated2.Y, 1f);
            GL.TexCoord3(1, 1, 1f);
            GL.Vertex3(planeTexturePositionRotated3.X, planeTexturePositionRotated3.Y, 1f);
            GL.TexCoord3(0, 1, 1f);
            GL.Vertex3(planeTexturePositionRotated4.X, planeTexturePositionRotated4.Y, 1f);
            GL.End();

            GL.Disable(EnableCap.Texture2D);

Параметры:

            GL.Viewport(0, 0, Param.XSize, Param.YSize);
            GL.Enable(EnableCap.DepthTest);
            GL.DepthFunc(DepthFunction.Always);
            GL.DepthMask(false);
            GL.Enable(EnableCap.Blend);
            GL.Disable(EnableCap.CullFace);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            GL.ClearColor(1, 1, 1, 0);

Апдейт:

            GL.Clear(ClearBufferMask.ColorBufferBit);
            GL.LoadIdentity();
            GL.Ortho(0, Param.XSize, Param.YSize, 0, -1.0f, 1.0f);

Самое забавное то, что мерцание возникает только в некоторых зонах экрана. При отключении фоновой текстуры ни мерцания, ни артефакта скроллинга нет.

#11
10:25, 30 июля 2013

Сделай так:

GL.Ortho(0, 1.0f, (float) Param.YSize / Param.XSize, 0, -1.0f, 1.0f);

И подели в транслейтах координаты тоже на Param.XSize.

(вообще, идеальная точность - если наоборот: делить всё на y. Но разницы почти нет.)

MDS
> На сколько я помню в старой спецификации можно было указывать типа glVertex3f
> glVertex3i .... но не важно, округляй до целого, и приводи к флоату
Здесь же при б-гмерзком шарпе этого нет, как я понял.

#12
15:36, 30 июля 2013

MDS, я тоже думал, что необходимо лишь один раз установить, но ничего не работает, быть может, особенность враппера.

Chipmunk, немного не понял, это для перевода в систему -1.0 - 1.0? Необходимо будет поменять все установленные координаты?

#13
16:17, 30 июля 2013

Невероятно, дали наводку на http://en.wikipedia.org/wiki/Nyquist–Shannon_sampling_theorem#Application_to_multivariable_signals_and_images
и на "This effect is not called flicker, it is called tearing. You see part of the old bitmap and part of the new bitmap. Which becomes very noticeable on moving objects, they appear jittery. Not fixable in Winforms, google "vertical blanking interval". – Hans Passant"
Заставил поток ждать 2мс после каждой отрисовки и все артефакты и мерцания исчезли. Что за дела? Есть ли не такой примитивный выход?

EDIT: заменил GL.Flush(); на GL.Finish(); - артефакты исчезли, но все стало очень медленным. Что происходит? :)

#14
20:32, 30 июля 2013

DummyUA
> Chipmunk, немного не понял, это для перевода в систему -1.0 - 1.0? Необходимо
> будет поменять все установленные координаты?
Была система:
0 .. screenWidth
0 .. screenHeight

После преобразования:
0 .. 1
0 .. screenHeight/screenWidth

То, что у тебя - это не tearing. При tearing не появляется белых участков, а просто верхняя половина картинки едет вбок.

ПрограммированиеФорум2D графика и изометрия

Тема в архиве.