Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

09.04.2013, 03:57

OpenTK (C# OpenGL Wrapper) - Wie lasse ich eine Bitmap korrekt anzeigen?

Hiho,

ich bin noch ein blutiger Anfänger in OpenGL und allgemein in 2D- und 3D Anwendungen und will nun ein Programm schreiben, dass mir Bilder anzeigen- und pixelweise bearbeiten kann. Da es sich später um sehr viele Bilder handelt reicht die performance, die ich mit einem multithreaded Programm erreiche bei weitem nicht aus.

Ich gehe also mit kleinen Schritten in Richtung meinem Ziel.
Habe auch schon ein komplettes Programm hierfür geschrieben.
Ich benutze C# (Visual Studio 10) mit dem OpenGL wrapper OpenTK der technisch gesehen angeblich kaum overhead hat.
Das einzige Problem an meinem Programm ist nun, dass das OpenGL window (kontext?) immer seine ClearColor behält, obwohl ich ja mein Bild angezeigt haben will und nicht nur eine leere Fläche.
Den code habe ich mit Consolenausgaben geprüft und er wid einwandfrei durchlaufen.
Auch werden keinerlei Exceptions geworfen oder sonstige Fehler, es passiert einfach nur nichts und ich hab mittlerweile keinen blassen schimmer mehr woran das liegen könnte ... :-(

Hier sind meine codes die ich mir durch recherchen, brainstorming und zugegebenermaßen auch teilweise copy'n paste zusammengewürfelt habe:

Vertex Shader:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
attribute vec4 a_position;
attribute vec2 a_texcoord;
varying vec2 v_texcoord;

void main()
{
    v_texcoord = a_texcoord.st;
    gl_Position = a_position;
}


Fragment Shader: (Pixelshader) Soll im moment keinerlei Änderungen am Bild vornehmen - nur zum test.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
varying vec2 v_texcoord;
uniform sampler2D u_texture_y;

void main()
{
    vec4 color;
    color.rgba = texture2D(u_texture_y, v_texcoord).rgba;                   
    gl_FragColor = color;
}


Diesen code benutze ich, um meine beiden Shader zur laufzeit zu compilen und ein program zu bauen mit dem ich dann später meine Bilder durch die GPU pipeline schleußen und bearbeiten kann.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
        private void CreateShaders(byte[] vsFile, byte[] fsFile, out int vertexObject, out int fragmentObject, out int program)
        {
            int status_code;
            string info;
            // Read shader files
            string vs = System.Text.Encoding.UTF8.GetString(
                DaltonEyes.Properties.Resources.testVertexShader);
            string fs = System.Text.Encoding.UTF8.GetString(
                DaltonEyes.Properties.Resources.testFragmentShader);
            // Setup shader objects
            vertexObject = GL.CreateShader(ShaderType.VertexShader);
            fragmentObject = GL.CreateShader(ShaderType.FragmentShader);
            // Compile vertex shader
            GL.ShaderSource(vertexObject, vs);
            GL.CompileShader(vertexObject);
            GL.GetShaderInfoLog(vertexObject, out info);
            GL.GetShader(vertexObject, ShaderParameter.CompileStatus, out status_code);
            if (status_code != 1)
            {
                throw new ApplicationException(info);
            }
            // Compile vertex shader
            GL.ShaderSource(fragmentObject, fs);
            GL.CompileShader(fragmentObject);
            GL.GetShaderInfoLog(fragmentObject, out info);
            GL.GetShader(fragmentObject, ShaderParameter.CompileStatus, out status_code);
            if (status_code != 1)
            {
                throw new ApplicationException(info);
            }
            program = GL.CreateProgram();
            GL.AttachShader(program, fragmentObject);
            GL.AttachShader(program, vertexObject);
            GL.LinkProgram(program);
            float[] vertexVertices = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };
            float[] textureVertices = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
            int handleAPosition = GL.GetAttribLocation(program, "a_position");
            int handleATexcoord = GL.GetAttribLocation(program, "a_texcoord");
            GL.EnableVertexAttribArray(handleAPosition);
            GL.EnableVertexAttribArray(handleATexcoord);
            GL.VertexAttribPointer(handleAPosition, 2, VertexAttribPointerType.Float, false, 0, vertexVertices);
            GL.VertexAttribPointer(handleATexcoord, 2, VertexAttribPointerType.Float, false, 0, textureVertices);
            GL.UseProgram(program);
        }


Mit dieser Methode lade ich die daten einer Bitmap in meine GPU und erhalte die textureId mit der ich zugriff auf die textur erhalte.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        public int LoadTexture(Bitmap bitmap)
        {
            int tex;
            GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);

            GL.GenTextures(1, out tex);
            GL.BindTexture(TextureTarget.Texture2D, tex);

            BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

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

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
            return tex;
        }


Hiermit initialisiere ich OpenGL und meinen OpenGL kontext window.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        int vertexShaderObject, fragmentShaderObject, shaderProgram;
        int vertexBufferObject, colorBufferObject, elementBufferObject;
        int currentTextureId;

        private void InitTexturing()
        {
            GL.Disable(EnableCap.CullFace);
            GL.Enable(EnableCap.Texture2D);
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
        }

        private void SetupViewport()
        {
            int w = glControl1.Width;
            int h = glControl1.Height;
            GL.ClearColor(Color.Black);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0,0)
            GL.Viewport(0, 0, w, h); // Use all of the glControl paintining area
        }

        private void OnLoadGL(object sender, EventArgs e)
        {
            this.GLContextLoaded = true;
            this.SetupViewport();
            this.InitTexturing();
        }


Mit diesem Methoden sollte eigentlich das Bild aus der Datei gelesen und gezeichnet werden, passieren tut leider nichts.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
        public void DrawImage(int image)
        {
            int w = glControl1.Width;
            int h = glControl1.Height;

            GL.MatrixMode(MatrixMode.Projection);
            GL.PushMatrix();
            GL.LoadIdentity();

            GL.MatrixMode(MatrixMode.Modelview);
            GL.PushMatrix();
            GL.LoadIdentity();

            GL.Disable(EnableCap.Lighting);

            GL.Enable(EnableCap.Texture2D);

            GL.BindTexture(TextureTarget.Texture2D, image);
            
            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0, 0); GL.Vertex3(0, 0, 0);
            GL.TexCoord2(0, h); GL.Vertex3(w, 0, 0);
            GL.TexCoord2(w, 0); GL.Vertex3(w, h, 0);
            GL.TexCoord2(w, h); GL.Vertex3(0, h, 0);

            GL.End();

            GL.Disable(EnableCap.Texture2D);
            GL.PopMatrix();

            GL.MatrixMode(MatrixMode.Projection);
            GL.PopMatrix();

            GL.MatrixMode(MatrixMode.Modelview);
        }

        private void Render()
        {
            if (!this.GLContextLoaded)
            {
                return;
            }
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            this.DrawImage(this.currentTextureId);

            glControl1.SwapBuffers();
        }

        private Bitmap currentBitmap = null;
        private void OnPaintGL(object sender, PaintEventArgs e)
        {
            currentBitmap = DaltonEyes.Properties.Resources.testImage;
            if (currentBitmap != null)
            {
                this.currentTextureId = this.LoadTexture(currentBitmap);
            }
            this.Render();
        }


Also was ich versuche, ist eine Rechteckige fläche durch Quad polygone zu zeichnen, die dann eben jene textur erhalten. Ich habe es iwie mal geschafft, dass dieses sog. Quad gezeichnet wurde (nur einfarbig) - allerdings hab ich sodann vor lauter euphorie den code so lange geändert, bis es dann doch nimmer ging ...

Ich hoffe ihr könnt mir meine Fehler aufzeigen und mir evtl. sogar erklären warum das so nicht funktionieren kann - wäre extrem dankbar!

Ist auch mein erster Beitrag in diesem Forum, also bitte nicht zu streng sein, wenn ich doch das falsche Forum hierfür erwischt habe.

LG,
Robbepop

idontknow

unregistriert

2

09.04.2013, 14:03

Mir scheint in deinem DrawImage aufruf fehlt der abschließende Draw-Call.

Bei dem Part steige ich leider aus (kann kein OpenGL), aber bezweifel stark, dass der für irgendwas nützlich ist! Bei deinem Programm hättest du eher Input Variablen im Shader (sowas wie: in vec3 pos; in vec2 tex;)

C#-Quelltext

1
2
3
4
5
6
7
8
float[] vertexVertices = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };
            float[] textureVertices = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
            int handleAPosition = GL.GetAttribLocation(program, "a_position");
            int handleATexcoord = GL.GetAttribLocation(program, "a_texcoord");
            GL.EnableVertexAttribArray(handleAPosition);
            GL.EnableVertexAttribArray(handleATexcoord);
            GL.VertexAttribPointer(handleAPosition, 2, VertexAttribPointerType.Float, false, 0, vertexVertices);
            GL.VertexAttribPointer(handleATexcoord, 2, VertexAttribPointerType.Float, false, 0, textureVertices);


Kann dir aber nicht sagen wie genau das funktioniert selber nie probiert.. dein Draw-Call scheint aber trotzdem auf jedenfalll zu fehlen.

Techie

Alter Hase

Beiträge: 717

Wohnort: Bayreuth

Beruf: Student | Hilfswissenschaftler in der Robotik

  • Private Nachricht senden

3

10.04.2013, 18:41

Tao, war der Vorgänger von OpenTK, Tao ist tot. OpenTK (tot).
Mittlerweile ist SharpGL das Projekt von dcen Entwicklern...
Mal sehen wie lange es dauert bis es auch tot ist..
I write my own game engines because if I'm going to live in buggy crappy filth, I want it to me my own - Ron Gilbert

DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

4

10.04.2013, 20:30

Abgesehen davon ist wohl so ziemlich alles an dem Code veraltet...

5

11.04.2013, 07:44

Hiho,

danke für die Antworten bisher.
Ich habe mich nommal hingesetzt und es endlich zum laufen gebracht, fragt mich bitte nicht wie genau.
Hier sind mal meine neuen codes für diejenigen, die das selbe problem haben.

Allerdings ist meine problemserie damit noch nicht beendet.
Zwar werden mir nun meine bilder als texturen generiert und angezeigt, allerdings muss ich hierfür mein shaderprogramm deaktivieren.
Sobald ich die linie "GL.UseProgram(program)" nichtmehr auskommentiere geht alles den bach runter und mir werden keinerlei frames mehr angezeigt.

Das traurige ist, dass ich jedoch die shader unbedingt brauche für den weiteren Projektverlauf, da ich damit vorhabe die bilder ein wenig zu verändern (fragmentshader).

Insgesamt bestehen aktuell noch zwei Probleme:
- Die Bilder werden ohne OpenGL schneller gerendert als mit. (Ohne OpenGL bedeutet, dass ich z.b. einem ComponentObjekt in meinem Fenster ein Image übergebe, dass beim nächsten rendervorgang vom betriebssystem gezeichnet wird.)
- Ich kann momentant keine Shaderprogramme benutzen.

Hier sind meine aktuellen codes und shader:

Vertex Shader: (sollte jetzt besser aussehen)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
varying vec2 texCoord;

void main()
{
    texCoord = gl_MultiTexCoord0.st;
    vec4 pos = gl_ModelViewMatrix * gl_Vertex;

    gl_Position = gl_ProjectionMatrix * pos;
}


Fragment Shader: (ebenfalls überarbeitet)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
varying vec2 texCoord;

void main()
{
    texCoord = gl_MultiTexCoord0.st;
    vec4 pos = gl_ModelViewMatrix * gl_Vertex;

    gl_Position = gl_ProjectionMatrix * pos;
}


Restlicher Code der sich grob verändert hat:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
        private void OnLoadGL(object sender, EventArgs e)
        {
            this.GLContextLoaded = true;
            this.CreateShaders(
                DaltonEyes.Properties.Resources.testVertexShader,
                DaltonEyes.Properties.Resources.testFragmentShader,
                out vertexShaderObject,
                out fragmentShaderObject,
                out shaderProgram);
            this.SetupViewport();
            this.InitTexturing();
        }

        public void DrawImage(int image)
        {
            int w = glControl.Width;
            int h = glControl.Height;

            GL.Disable(EnableCap.Lighting);

            GL.Enable(EnableCap.Texture2D);

            GL.BindTexture(TextureTarget.Texture2D, image);

            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0, 1); GL.Vertex3(0, 0, 0);
            GL.TexCoord2(1, 1); GL.Vertex3(w, 0, 0);
            GL.TexCoord2(1, 0); GL.Vertex3(w, h, 0);
            GL.TexCoord2(0, 0); GL.Vertex3(0, h, 0);

            GL.End();

            GL.Disable(EnableCap.Texture2D);
            GL.PopMatrix();
        }

        private bool awaitingFrame = true;
        private void OnPaintGL(object sender, PaintEventArgs e)
        {
            if (this.currentBitmap != null)
            {
                Bitmap bmp = (Bitmap)this.currentBitmap;
                this.awaitingFrame = true;
                this.currentTextureId = this.LoadTexture(bmp);
                this.Render();
                bmp.Dispose();
                GL.DeleteTexture(this.currentTextureId);
            }
        }

        private void OnNewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            if (this.awaitingFrame)
            {
                this.awaitingFrame = false;
                this.currentBitmap = (Bitmap)eventArgs.Frame.Clone();
                this.FPSUpdateFrame(true);
                this.glControl.Invalidate();
            }
            else
            {
                this.FPSUpdateFrame(false);
            }
        }


Bei der bereits geposteten CreateShader methode hab ich lediglich besagte Zeile "GL.UseProgram(program)" auskommentiert.

@Technie: Wie? Du meinst, dass "the fiddler" nun nichtmehr OpenTK, sondern SharpGL entwickelt? Das klingt für mich sehr komisch. Allerdings find ich SharpGL im vergleich zu OpenTK echt hässlich und zudem soll OpenTK ja auch ein relativ dünner wrapper sein, was ich ebenfalls gut finde. =)

@DeKugelschieber: Deine Aussage klingt für mich höchst interessant. Wieso ist mein code denn veraltet bzw. was genau muss ich tun, damit er es nichtmehr ist? Wie bereits erwähnt bin ich ein absoluter neueinsteiger in OpenGL und recherchier erst die letzten tage etwas damit rum und weis dementsprechend so gut wie nichts darüber wie ein modernes OpenGL programm auszusehen hat da ich mein wissen auf evtl. veralteten Quellen fundiere. :-(

mfg,
Robbepop

stef

Treue Seele

Beiträge: 246

Wohnort: Kassel

Beruf: Softwareentwickler

  • Private Nachricht senden

6

11.04.2013, 15:03

Wieso ist mein code denn veraltet bzw. was genau muss ich tun, damit er es nichtmehr ist?

Du verwendest Immediate mode ( glBegin() ... glEnd() ).
Das ist extrem langsam und gilt schon seit Uhrzeiten als veraltet (depricated).
Wenn du modernes OpenGL programmieren willst verwende für deine Geometriedaten
VertexBufferObjects (VBO) in Kombination mit VertexArrayObjects (VAO zum organisieren von VBO's).
Wenn du VBO/VAO und shader verwendest bist du up to date (benötigt aber min. OpenGL 3.0).
"In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg." — Bjarne Stroustrup.

Werbeanzeige