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

Pascal

Frischling

  • »Pascal« ist der Autor dieses Themas

Beiträge: 13

Wohnort: Kassel (Hessen)

Beruf: Schüler

  • Private Nachricht senden

1

30.07.2014, 21:40

OpenGL: Problem mit Blendmaps

Hallo liebe Community,

Ich versuche ein Terrainfading-System für mein OpenGL (orthogonaler Modus) Spiel zu implementieren.
Ich habe mir dazu das Tutorial (http://wiki.delphigl.com/index.php/Tutorial_Lektion_7) durchgelesen und mich an dessen Quellcode orientiert und verwende die selben glblendmodes.


Mein Quellcode:

C-/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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
void CSprite::renderblend (GLfloat x, GLfloat y, GLfloat degrees, GLuint ID, int BlendtextureID, float BlendtextureAngle, int BlendmapID, float Blendmapangle)
{
    if (IsOnScreen (x, y, mTextureWidth [ID], mTextureHeight [ID]) == false)
        return;

    glPushMatrix ();
    glDisable(GL_BLEND);

    //If the texture exists
    if(g_pSpriteManager->m_pBlendmaps->GetID (BlendmapID) != 0)
    {

        //Texture coordinates
        GLfloat texTop = 0.f;
        GLfloat texBottom = 1.f;
        GLfloat texLeft = 0.f;
        GLfloat texRight = 1.f;

        //Vertex coordinates
        GLfloat quadWidth = static_cast<GLfloat> (mTextureWidth [ID]);
        GLfloat quadHeight = static_cast<GLfloat> (mTextureHeight [ID]);

        //Move to rendering point
        glTranslatef( x + quadWidth / 2.f, y + quadHeight / 2.f, 0.f);

        //Rotate around rendering point 
        glRotatef( Blendmapangle, 0.f, 0.f, 1.f );

        //Set texture ID
        glBindTexture(GL_TEXTURE_2D, g_pSpriteManager->m_pBlendmaps->GetID (BlendmapID));

        //Render textured quad
        glBegin( GL_QUADS ); 
        glTexCoord2f( texLeft, texTop );     glVertex2f( -quadWidth / 2.f, -quadHeight / 2.f ); 
        glTexCoord2f( texRight, texTop );    glVertex2f( quadWidth / 2.f, -quadHeight / 2.f ); 
        glTexCoord2f( texRight, texBottom ); glVertex2f( quadWidth / 2.f, quadHeight / 2.f ); 
        glTexCoord2f( texLeft, texBottom );  glVertex2f( -quadWidth / 2.f, quadHeight / 2.f ); 
        glEnd();

        //Unbind texture ID
        glBindTexture( GL_TEXTURE_2D, NULL);
    }

    glPopMatrix ();
    glPushMatrix ();

    glEnable(GL_BLEND);
    glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
    //If the texture exists
    if( mTextureIDArray [ID] != 0)
    {

        //Texture coordinates
        GLfloat texTop = 0.f;
        GLfloat texBottom = 1.f;
        GLfloat texLeft = 0.f;
        GLfloat texRight = 1.f;

        //Vertex coordinates
        GLfloat quadWidth = static_cast<GLfloat> (mTextureWidth [ID]);
        GLfloat quadHeight = static_cast<GLfloat> (mTextureHeight [ID]);

        //Move to rendering point
        glTranslatef( x + quadWidth / 2.f, y + quadHeight / 2.f, 0.f);

        //Rotate around rendering point 
        glRotatef( degrees, 0.f, 0.f, 1.f );

        //Set texture ID
        glBindTexture(GL_TEXTURE_2D, mTextureIDArray [ID]);

        //Render textured quad
        glBegin( GL_QUADS ); 
        glTexCoord2f( texLeft, texTop );     glVertex2f( -quadWidth / 2.f, -quadHeight / 2.f ); 
        glTexCoord2f( texRight, texTop );    glVertex2f( quadWidth / 2.f, -quadHeight / 2.f ); 
        glTexCoord2f( texRight, texBottom ); glVertex2f( quadWidth / 2.f, quadHeight / 2.f ); 
        glTexCoord2f( texLeft, texBottom );  glVertex2f( -quadWidth / 2.f, quadHeight / 2.f ); 
        glEnd();

        //Unbind texture ID
        glBindTexture( GL_TEXTURE_2D, NULL);
    }




    glPopMatrix ();
    glPushMatrix ();
    glBlendFunc(GL_SRC_COLOR,GL_ONE);

    //If the texture exists
    if(mTextureIDArray [BlendtextureID] != 0)
    {

        //Texture coordinates
        GLfloat texTop = 0.f;
        GLfloat texBottom = 1.f;
        GLfloat texLeft = 0.f;
        GLfloat texRight = 1.f;

        //Vertex coordinates
        GLfloat quadWidth = 100.f;
        GLfloat quadHeight = 100.f;

        //Move to rendering point
        glTranslatef( x + quadWidth / 2.f, y + quadHeight / 2.f, 0.f);

        //Rotate around rendering point 
        glRotatef( BlendtextureAngle, 0.f, 0.f, 1.f );

        //Set texture ID
        glBindTexture(GL_TEXTURE_2D, mTextureIDArray [BlendtextureID]);

        //Render textured quad
        glBegin( GL_QUADS ); 
        glTexCoord2f( texLeft, texTop );     glVertex2f( -quadWidth / 2.f, -quadHeight / 2.f ); 
        glTexCoord2f( texRight, texTop );    glVertex2f( quadWidth / 2.f, -quadHeight / 2.f ); 
        glTexCoord2f( texRight, texBottom ); glVertex2f( quadWidth / 2.f, quadHeight / 2.f ); 
        glTexCoord2f( texLeft, texBottom );  glVertex2f( -quadWidth / 2.f, quadHeight / 2.f ); 
        glEnd();

        //Unbind texture ID
        glBindTexture( GL_TEXTURE_2D, NULL);
    }

    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // Reset Blendmode


Das Problem ist, wie auf den Bildern im Anhang zu sehen, das die eine Seite zu dunkel und die andere zu hell ist.

Deshalb meine Frage: Sind die glBlendFunc Befehle falsch oder der ganze Ansatz?

Ich würde mich sehr freuen wenn ihr mir helfen könnt, da ich das Blending system nicht wirklich verstehe (Tutorial- oder Buchtipps?)
»Pascal« hat folgendes Bild angehängt:
  • blendmap_0.bmp
»Pascal« hat folgende Datei angehängt:

2

31.07.2014, 12:54

Grundlagen
Das Blending funktioniert nach folgender Formel *:
§Ergebnis = sourceFactor * sourceColor + destinationFactor * destinationColor§

Mit der Funktion glBlendFunc kannst du die Factors einstellen:

C-/C++-Quelltext

1
2
3
4
glBlendFunc(GL_ONE, GL_ZERO); // default, E = 1 * sourceColor + 0 * destinationColor = sourceColor
glBlendFunc(GL_ZERO, GL_ONE); // E = destinationColor
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // E = destinationColor * sourceColor + sourceColor * destinationColor
...
siehe https://www.opengl.org/sdk/docs/man2/xhtml/glBlendFunc.xml

* Mit der Funktion glBlendEquation kannst du die gesamte Gleichung noch umschalten:

C-/C++-Quelltext

1
2
3
glBlendEquation(GL_FUNC_ADD);  // default, E = sourceFactor * sourceColor + destFactor * destColor
glBlendEquation(GL_FUNC_SUBTRACT); // E = sourceFactor * sourceColor - destFactor * destColor
...
siehe https://www.opengl.org/sdk/docs/man2/xht…endEquation.xml

Zur Verdeutlichung von dem, was du da gerade mit deinem Code machst
§B§ sei der Index für die Blendmap
§T1§ sei der Index für die erste Textur
§T2§ sei der Index für die zweite Textur.

Beim ersten Pass zeichnest du die Blendmap und schaltest jegliches Blending aus. Also hast du eine resultierende Farbe von:
§\vec{r_1} = (r_B, g_B, b_B, a_B)§

Beim zweiten Pass zeichnest du nun die erste Textur und nutzt glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);. Die resultierende Farbe ist die folgende:
§\vec{r_2} = \vec{r_1} * (r_{T1}, g_{T1}, b_{T1}, a_{T1}) + (r_{T1}, g_{T1}, b_{T1}, a_{T1}) * \vec{r_1} = 2 \vec{r_1}(r_{T1}, g_{T1}, b_{T1}, a_{T1})§
Das sieht mir schon etwas sinnlos aus, aber gehen wir mal weiter. ;)

Beim dritten Pass zeichnest du nun die zweite Textur mit glBlendFunc(GL_SRC_COLOR,GL_ONE);. Folgendes kommt raus:
§\vec{r_3} = (r_{T2}, g_{T2}, b_{T2}, a_{T2}) * (r_{T2}, g_{T2}, b_{T2}, a_{T2}) + (1, 1, 1, 1) * \vec{r_2}§

Jetzt können wir das ganze einsetzen und zusammenfassen:
§\vec{r} = (r_{T2}, g_{T2}, b_{T2}, a_{T2}) ^ 2 + 2 * (r_B, g_B, b_B, a_B) * (r_{T1}, g_{T1}, b_{T1}, a_{T1})§

Das sieht doch schon sehr seltsam aus. Ich vermute du möchtest nun eher folgendes erreichen:
§\vec{r} = (r_B, g_B, b_B, a_B) * (r_{T1}, g_{T1}, b_{T1}, a_{T1}) + (1 - (r_B, g_B, b_B, a_B)) * (r_{T2}, g_{T2}, b_{T2}, a_{T2})§

Splitten wir das wieder in mehrere Passes, könnte folgendes heraus kommen (lineare Interpolation):
§\vec{r_1} = (r_B, g_B, b_B, a_B)§
§\vec{r_2} = \vec{r_1} * (r_{T1}, g_{T1}, b_{T1}, a_{T1}) + 0 * \vec{r_1}§
§\vec{r_3} = (1 - \vec{r_2}) * (r_{T2}, g_{T2}, b_{T2}, a_{T2}) + 1 * \vec{r_2}§

In Code-Form könnte das so aussehen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
// pass 1:
glDisable(GL_BLEND); /* entspricht: */ glBlendFunc(GL_ONE, GL_ZERO);

// pass 2:
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);

// pass 3:
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);


Ich habe dir jetzt einen möglichen Weg gezeigt, es gibt aber sicher noch andere Wege das zu implementieren. Beispielsweise kann man mithilfe eines Shaders das ganze Konstrukt in einem Pass erledigen, indem man dem Shader mehrere Texturen übergibt und diese im Pixel Shader zusammen gemischt werden. Dann kannst du auch beliebig andere Formeln nutzen und ggf. eigene Filter beim Sampling anwenden.

Außerdem nutzt du derzeit für die Blendmap alle Kanäle. Um den Datentransfer zu minimieren, bietet es sich an, für die Blendmap nur einen Kanal (den Alpha-Kanal) zu verwenden. OpenGL unterstützt dann explizit das Angeben von GL_SRC_ALPHA bzw. GL_DST_ALPHA womit du auf diesen Kanal zugreifen kannst.

Lernen kannst du das ganze am besten, indem du es einfach selbst ausprobierst und ggf. bei Fragen googlest. Wenn du dort keine Antwort bekommst, kannst steht das Forum hier ja auch noch zur Verfügung ;)
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »iSmokiieZz« (31.07.2014, 13:12)


Pascal

Frischling

  • »Pascal« ist der Autor dieses Themas

Beiträge: 13

Wohnort: Kassel (Hessen)

Beruf: Schüler

  • Private Nachricht senden

3

31.07.2014, 14:06

Vielen Dank für die ausführliche Antwort! :thumbsup:
Ich werde mich mal in das Thema Shader reinarbeiten.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

4

31.07.2014, 17:24

Nur für den Fall möchte ich mal vorsichtig darauf hinweisen, dass in dem Tutorial sehr altes deprecated OpenGL benutzt wird und zudem überwiegend Techniken, die heutzutage nicht mehr empfehlenswert sind. Ich würde Tutorials von dort als einzige Anlaufstelle mit Vorsicht betrachten und je nach dem wenn möglich eine andere Anlaufstelle suchen.

Werbeanzeige

Ähnliche Themen