Code-Beispiel
OpenGL/GLSL Radial Blur
Lizenz: | Erster Autor: | Letzte Bearbeitung: |
k. A. | schildron | 10.02.2011 |
Im folgenden Beispiel möchte ich zeigen, wie man einen Radial Blur Effekt erstellen kann. Dazu verwenden wir die OpenGL Shading Language. Sie ermöglicht uns, auf der Grafikkarte spezielle Grafikeffekte darzustellen.
Benötigt wird eine OpenGL 2.0 taugliche Grafikkarte. Wenn das folgende Programm nicht funktioniert, hilft möglicherweise ein Update des Grafiktreibers.
Das Demoprogramm besteht aus 3 Teilen:
- Hauptprogramm
- Shadercode (RadialBlur.shader im shaders Unterordner)
- Eine Textur
Die unten folgende Textur heißt "Ziegelwand.png" und kann für ein richtiges Spiel durch eine Textur, die das Spielgeschehen abbildet, ersetzt werden (Stichwort: Render to Texture).
Ziegelwand
Als erstes der Code der Hauptdatei:
'-----------------------------------------------------
'2011 by Schildron
'-----------------------------------------------------
'Ein großer Dank gilt:
' * http://wiki.delphigl.com/ für viel Hintergrundwissen und dem Aufbau des Radial Blur Shaders
' * http://www.freebasic.net/forum/ für Informationen, wie man GLSL mit FreeBASIC nutzt
'-----------------------------------------------------
Dim Shared As Integer Breite, Hohe
Dim As String Tastendruck
Breite = 800
Hohe = 600
#Include "fbgfx.bi"
#Include "fbpng.bi"
#Include Once "GL/gl.bi"
#Include Once "GL/glu.bi"
#Include "\gl\glext.bi"
'-------------------------
'Declarationen
'-------------------------
Declare Sub ScreenTexture()
Declare Function Init_Shader( File_Name As String, Shader_Type As Integer )As GlHandleARB
Declare Sub Gather_Extensions()
'shaders
Common Shared _shader100_ As Integer
Common Shared glCreateShaderObjectARB As PFNglCreateShaderObjectARBPROC
Common Shared glShaderSourceARB As PFNglShaderSourceARBPROC
Common Shared glGetShaderSourceARB As PFNglGetShaderSourceARBPROC
Common Shared glCompileShaderARB As PFNglCompileShaderARBPROC
Common Shared glDeleteObjectARB As PFNglDeleteObjectARBPROC
Common Shared glCreateProgramObjectARB As PFNglCreateProgramObjectARBPROC
Common Shared glAttachObjectARB As PFNglAttachObjectARBPROC
Common Shared glUseProgramObjectARB As PFNglUseProgramObjectARBPROC
Common Shared glLinkProgramARB As PFNglLinkProgramARBPROC
Common Shared glValidateProgramARB As PFNglValidateProgramARBPROC
Common Shared glGetObjectParameterivARB As PFNglGetObjectParameterivARBPROC
Common Shared glGetInfoLogARB As PFNglGetInfoLogARBPROC
Common Shared glGetUniformLocationARB As PFNglGetUniformLocationARBPROC
Common Shared glUniform1iARB As PFNglUniform1iARBPROC
Common Shared glUniform2ivARB As PFNglUniform2ivARBPROC
Common Shared glUniform1fARB As PFNglUniform1fARBPROC
Common Shared glUniform2fvARB As PFNglUniform2fvARBPROC
Common Shared glUniform3fvARB As PFNglUniform3fvARBPROC
'-------------------------
' das Fenster öffnen
'-------------------------
Screen 19, 32, , 2
Dim As GlHandleARB Vertex_Shader, Shader_Program
Dim As Gluint Shader_Compile_Success
Dim As GlHandleARB Fragment_Shader
Dim As GlInt TimerLoc
Dim As Integer use_shader = -1
Dim Shared As Single BlurPower = 0.08, BlurFactor = 12 ''Hier die wichtigsten Parameter für Blur einstellen
Dim As GlInt BlurPowerLoc, BlurFactorLoc, DisplayHoheLoc, DisplayBreiteLoc
Dim Shared As Integer errlog
errlog = FreeFile
'-------------------------
' Open-GL Init
'-------------------------
glViewport 0, 0, Breite, Hohe ' den Current Viewport auf eine Ausgangsposition setzen
glMatrixMode GL_PROJECTION ' Den Matrix-Modus Projection wählen
glLoadIdentity ' Diesen Modus auf Anfangswerte setzen
gluPerspective 45.0, Breite/Hohe, 0.1, 100.0 ' Grundeinstellungen des Anezeigefensters festlegen
glMatrixMode GL_MODELVIEW ' Auf den Matrix-Modus Modelview schalten
glLoadIdentity ' und auch diesen auf Anfangswerte setzen
glClearColor(0.9,0.9,0.9,0.0) ' Setze Farbe für löschen auf Mittelgrau
glClearDepth 1.0 ' Depth-Buffer Löschen erlauben
glEnable GL_DEPTH_TEST ' den Tiefentest GL_DEPTH_TEST einschalten
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT 'Tiefen- und Farbpufferbits löschen
'---------------------------
'HAUPTTEIL
'---------------------------
Dim Shared As Integer Ptr LoadRenderTextur
LoadRenderTextur = ImageCreate(Breite, Hohe, 0, 32)
Dim Shared As UInteger RenderTextur
glGenTextures 1, @RenderTextur
glBindTexture GL_TEXTURE_2D, RenderTextur
glTexImage2D GL_TEXTURE_2D, 0, GL_RGB, Breite, Hohe, 0, GL_RGBA, GL_UNSIGNED_BYTE, LoadRenderTextur'+Len(FB.IMAGE)
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
Dim Shared As UInteger BackgroundTextur
glGenTextures 1, @BackgroundTextur
glBindTexture GL_TEXTURE_2D, BackgroundTextur
glTexImage2D GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, png_load("Ziegelwand.png",PNG_TARGET_OPENGL)'+Len(FB.IMAGE)
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
Open Cons For Output As #errlog
Gather_Extensions()
If _shader100_ <> 0 Then
Fragment_Shader = Init_Shader( "Shaders/RadialBlur.shader", GL_FRAGMENT_SHADER_ARB )
Shader_Program = GlCreateProgramObjectARB()
glAttachObjectARB( Shader_Program, Fragment_Shader )
glLinkProgramARB( Shader_Program )
GlValidateProgramARB( Shader_Program )
glGetObjectParameterivARB( Shader_Program, GL_OBJECT_VALIDATE_STATUS_ARB, @Shader_Compile_Success )
If Shader_Compile_Success = 0 Then
Print #errlog, "Fehler beim GLSL kompilieren!"
Sleep 1000, 1
Close #errlog
ImageDestroy LoadRenderTextur
End
End If
'This gets the memory location of variable("name"), so that we can send data to the gpu at the correct address.
BlurPowerLoc = glGetUniformLocationARB( Shader_Program, StrPtr("BlurPower") )
BlurFactorLoc = glGetUniformLocationARB( Shader_Program, StrPtr("BlurFactor") )
DisplayBreiteLoc = glGetUniformLocationARB( Shader_Program, StrPtr("Breite") )
DisplayHoheLoc = glGetUniformLocationARB( Shader_Program, StrPtr("Hohe") )
Print #errlog, "Variablen wurden dem Shader uebergeben!"
Else
Print #errlog, "OpenGL Shader Language wird von Ihrer Grafikkarte nicht unterstutzt!"
Print #errlog, "Diese Demo wird nicht funktionieren wie erwartet!"
End If
'-------------------------
'in den GlOrtho Modus schalten
'-------------------------
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, breite, 0, hohe, -256, 256)
Do Until Tastendruck = Chr(27)
'---------------------------
'ProgrammSchleife
'---------------------------
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
Tastendruck = Inkey
glPushMatrix
ScreenTexture()
If _shader100_ Then
If use_shader Then
glUseProgramObjectARB( Shader_Program )
'Dem Shader die externen Variablen einpflanzen
glUniform1fARB( BlurPowerLoc, BlurPower )
glUniform1fARB( BlurFactorLoc, BlurFactor )
glUniform1iARB( DisplayBreiteLoc, Breite )
glUniform1iARB( DisplayHoheLoc, Hohe )
Else
glUseProgramObjectARB( 0 )
End If
End If
glPopMatrix
GlFlush
Flip
'---------------------------
'Ende der Schleife
'---------------------------
Loop
ImageDestroy LoadRenderTextur
End
Sub ScreenTexture()
'---------------------------
'Eine Textur auf das Gesamte Fenster legen
'---------------------------
glEnable GL_TEXTURE_2D
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
glBindTexture GL_TEXTURE_2D, BackgroundTextur
glBegin GL_QUADS
glTexCoord2d 0,1 : glVertex3f 0, hohe, -6.0
glTexCoord2d 1,1 : glVertex3f breite, hohe, -6.0
glTexCoord2d 1,0 : glVertex3f breite, 0, -6.0
glTexCoord2d 0,0 : glVertex3f 0, 0, -6.0
glEnd
glDisable GL_TEXTURE_2D
End Sub
Function Init_Shader( File_Name As String, Shader_Type As Integer )As GlHandleARB
'---------------------------
'Den Shader-Programmcode aus der externen Datei laden
'---------------------------
Dim As Integer i
Dim As Integer Line_Cnt
Dim As String Shader_Text, tString
Dim As Gluint Shader_Compile_Success
Dim As GlHandleARB Shader
Dim As UInteger FileNum = FreeFile
Open File_Name For Binary As #FileNum
Do While Not EOF(FileNum)
Line Input #FileNum, tString
Shader_Text += tString + Chr( 13, 10 )
Loop
Close #FileNum
Dim As GLcharARB Ptr table(0) => { StrPtr( Shader_Text ) }
Shader = glCreateShaderObjectARB( Shader_Type )
glShaderSourceARB( Shader, 1, @table(0), 0 )
glCompileShaderARB( Shader )
glGetObjectParameterivARB( Shader, GL_OBJECT_COMPILE_STATUS_ARB, @Shader_Compile_Success )
If Shader_Compile_Success = 0 Then
Dim As Gluint infologsize
glGetObjectParameterivARB( Shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, @infoLogSize)
Dim As GlByte infolog(InfoLogSize)
glGetInfoLogARB( Shader, InfoLogSize, 0, @infoLog(0))
tString=""
For i = 0 To InfoLogSize-1
tString+=Chr(InfoLog(i))
Next
Print #errlog, "Shader Fehlermeldungen:"
Print #errlog, tString
Return 0
Else
Return Shader
End If
End Function
Sub Gather_Extensions()
Dim extensions As String
ScreenControl FB.GET_GL_EXTENSIONS, extensions
If (InStr(extensions, "GL_ARB_shading_language_100") <> 0) Then
Print #errlog, "GL_ARB_shading_language_100 wird unterstutzt!"
_shader100_ = 1
glCreateShaderObjectARB = ScreenGLProc("glCreateShaderObjectARB")
glShaderSourceARB = ScreenGLProc("glShaderSourceARB")
glGetShaderSourceARB = ScreenGLProc("glGetShaderSourceARB")
glCompileShaderARB = ScreenGLProc("glCompileShaderARB")
glDeleteObjectARB = ScreenGLProc("glDeleteObjectARB")
glCreateProgramObjectARB = ScreenGLProc("glCreateProgramObjectARB")
glAttachObjectARB = ScreenGLProc("glAttachObjectARB")
glUseProgramObjectARB = ScreenGLProc("glUseProgramObjectARB")
glLinkProgramARB = ScreenGLProc("glLinkProgramARB")
glValidateProgramARB = ScreenGLProc("glValidateProgramARB")
glGetInfoLogARB = ScreenGLProc("glGetInfoLogARB")
glGetObjectParameterivARB = ScreenGLProc("glGetObjectParameterivARB")
glGetUniformLocationARB = ScreenGLProc("glGetUniformLocationARB")
glUniform1iARB = ScreenGLProc("glUniform1iARB")
glUniform2ivARB = ScreenGLProc("glUniform2ivARB")
glUniform1fARB = ScreenGLProc("glUniform1fARB")
glUniform2fvARB = ScreenGLProc("glUniform2fvARB")
glUniform3fvARB = ScreenGLProc("glUniform3fvARB")
Else
Print #errlog, "GL_ARB_shading_language_100 wird NICHT unterstutzt!"
End If
Print #errlog, " "
End Sub
Der nächste Codeteil ist für den eigentlichen Shader zuständig. Er muss im Unterordner shaders mit dem Namen "RadialBlur.shader" abgespeichert werden:
// RadialBlur - Shader
uniform float BlurPower;
uniform float BlurFactor;
uniform int Breite;
uniform int Hohe;
uniform sampler2D BackgroundTextur; // scene texture
vec2 radial_size = vec2(1/Breite,1/Hohe); // texel size
float radial_blur = BlurPower; // blur factor
uniform float radial_bright = 1; // bright factor
uniform vec2 radial_origin = vec2(0.5,0.5); // blur origin
void main(void)
{
vec2 TexCoord = vec2(gl_TexCoord[0]);
vec4 SumColor = vec4(0.0, 0.0, 0.0, 0.0);
TexCoord += radial_size * 0.5 - radial_origin;
for (int i = 0; i < BlurFactor; i++)
{
float scale = 1.0 - radial_blur * (float(i) / (BlurFactor - 1));
SumColor += texture2D(BackgroundTextur, TexCoord * scale + radial_origin);
}
gl_FragColor = SumColor / (BlurFactor - 1) * radial_bright;
}
Wenn alles richtig funktioniert, sollte die Ziegelwand von der Mitte aus nach außen verwischt werden.
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|