Jump to content
  • Advertisement
Sign in to follow this  
Nicolas Rougier

OpenGL Tricky question on shader

This topic is 2663 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

[font="Helvetica"]Hi folks,[/font] [font="Helvetica"]I've been playing with gaussian texture filtering using shaders and I obtained a strange "grid" effect on a completely uniform texture. Since all fragments get the same processing and same neighbouring values,I wonder if the grid is the result of some kind of artifact with floating points or the way texture coordinates are interpolated. Or I missed something completely obvious…[/font] [font="Helvetica"]I attached the (python) code below and the vertex/fragment is at the top of the file.[/font]

[font="Helvetica"]Nicolas[/font]



[font="Helvetica"][source lang="python"][/font][font="Helvetica"] [/font]

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import math
import ctypes
import numpy as np
import OpenGL.GL as gl
import OpenGL.GLUT as glut

vert = '''
void main()
{
gl_FrontColor = gl_Color;
gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}
'''


frag = '''
float
gaussian(float x)
{
float PI = 3.14159265358979323846264;
return exp(-2.0 * x * x) * sqrt(2.0 / PI);
}

vec4
filter( float x, vec4 c0, vec4 c1, vec4 c2, vec4 c3 )
{
vec4 r = c0 * gaussian(x+1.0); // h.x;
r += c1 * gaussian(x+0.0); // h.y;
r += c2 * gaussian(1.0-x); // h.z;
r += c3 * gaussian(2.0-x); // h.w;
return r;
}

vec4
interpolate( sampler2D texture, vec2 uv, vec2 pixel )
{
vec2 texel = uv/pixel - vec2(0.5,0.5) ;
vec2 f = fract(texel);
texel = (texel-fract(texel)+vec2(0.001,0.001))*pixel;

vec4 t0 = filter( f.x,
texture2D( texture, texel + vec2(-1, -1)*pixel ),
texture2D( texture, texel + vec2( 0, -1)*pixel ),
texture2D( texture, texel + vec2( 1, -1)*pixel ),
texture2D( texture, texel + vec2( 2, -1)*pixel ) );

vec4 t1 = filter( f.x,
texture2D( texture, texel + vec2(-1, 0)*pixel ),
texture2D( texture, texel + vec2( 0, 0)*pixel ),
texture2D( texture, texel + vec2( 1, 0)*pixel ),
texture2D( texture, texel + vec2( 2, 0)*pixel ) );

vec4 t2 = filter( f.x,
texture2D( texture, texel + vec2(-1, 1)*pixel ),
texture2D( texture, texel + vec2( 0, 1)*pixel ),
texture2D( texture, texel + vec2( 1, 1)*pixel ),
texture2D( texture, texel + vec2( 2, 1)*pixel ) );

vec4 t3 = filter( f.x,
texture2D( texture, texel + vec2(-1, 2)*pixel ),
texture2D( texture, texel + vec2( 0, 2)*pixel ),
texture2D( texture, texel + vec2( 1, 2)*pixel ),
texture2D( texture, texel + vec2( 2, 2)*pixel ) );

return filter( f.y, t0, t1, t2, t3 );
}

uniform vec2 pixel;
uniform sampler2D texture;
void main()
{
gl_FragColor = interpolate(texture, gl_TexCoord[0].xy, pixel);
}
'''



class Shader:
def __init__(self, vert = None, frag = None, name=''):
self.uniforms = {}
self.name = name
self.handle = gl.glCreateProgram()
self.linked = False
self._build_shader(vert, gl.GL_VERTEX_SHADER)
self._build_shader(frag, gl.GL_FRAGMENT_SHADER)
self._link()

def _build_shader(self, strings, stype):
count = len(strings)
if count < 1:
return
shader = gl.glCreateShader(stype)
gl.glShaderSource(shader, strings)
gl.glCompileShader(shader)
status = gl.glGetShaderiv(shader, gl.GL_COMPILE_STATUS)
if not status:
print gl.glGetShaderInfoLog(shader)
else:
gl.glAttachShader(self.handle, shader)

def _link(self):
gl.glLinkProgram(self.handle)
temp = ctypes.c_int(0)
gl.glGetProgramiv(self.handle, gl.GL_LINK_STATUS, ctypes.byref(temp))
if not temp:
gl.glGetProgramiv(self.handle, gl.GL_INFO_LOG_LENGTH, ctypes.byref(temp))
log = gl.glGetProgramInfoLog(self.handle)
print log
else:
self.linked = True

def bind(self):
gl.glUseProgram(self.handle)

def unbind(self):
gl.glUseProgram(0)

def uniformf(self, name, *vals):
loc = self.uniforms.get(name, gl.glGetUniformLocation(self.handle,name))
self.uniforms[name] = loc
if len(vals) in range(1, 5):
{ 1 : gl.glUniform1f,
2 : gl.glUniform2f,
3 : gl.glUniform3f,
4 : gl.glUniform4f
}[len(vals)](loc, *vals)

def uniformi(self, name, *vals):
loc = self.uniforms.get(name, gl.glGetUniformLocation(self.handle,name))
self.uniforms[name] = loc
if len(vals) in range(1, 5):
{ 1 : gl.glUniform1i,
2 : gl.glUniform2i,
3 : gl.glUniform3i,
4 : gl.glUniform4i
}[len(vals)](loc, *vals)



if __name__ == '__main__':
import sys

def on_display( ):
gl.glClearColor(1,1,1,1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

x,y,w,h = gl.glGetIntegerv(gl.GL_VIEWPORT)
gl.glEnable( gl.GL_BLEND )
gl.glBlendFunc (gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glColor( 1, 0, 0, 1 )

shader.bind()
gl.glEnable( gl.GL_TEXTURE_2D )
gl.glActiveTexture( gl.GL_TEXTURE0 )
gl.glBindTexture( gl.GL_TEXTURE_2D, texture_id)
shader.uniformi('texture', 0)
shader.uniformf('pixel', 1.0/Z.shape[0], 1.0/Z.shape[1])
gl.glBegin( gl.GL_QUADS )
gl.glTexCoord2f( 0, 1 ), gl.glVertex2f( x, y )
gl.glTexCoord2f( 0, 0 ), gl.glVertex2f( x, y+h )
gl.glTexCoord2f( 1, 0 ), gl.glVertex2f( x+w, y+h )
gl.glTexCoord2f( 1, 1 ), gl.glVertex2f( x+w, y )
gl.glEnd()
shader.unbind()
glut.glutSwapBuffers( )


def on_reshape( width, height ):
gl.glViewport( 0, 0, width, height )
gl.glMatrixMode( gl.GL_PROJECTION )
gl.glLoadIdentity( )
gl.glOrtho( 0, width, 0, height, -1, 1 )
gl.glMatrixMode( gl.GL_MODELVIEW )
gl.glLoadIdentity( )


def on_keyboard( key, x, y ):
if key == '\033':
sys.exit( )

glut.glutInit( sys.argv )
glut.glutInitDisplayMode( glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH )
glut.glutCreateWindow( "glumpy filters" )
glut.glutReshapeWindow( 800, 800 )
glut.glutDisplayFunc( on_display )
glut.glutReshapeFunc( on_reshape )
glut.glutKeyboardFunc( on_keyboard )

def func3(x,y):
return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)
x = np.linspace(-3.0, 3.0, 32)
y = np.linspace(-3.0, 3.0, 32)
Z = func3(*np.meshgrid(x, y))
Z = (Z-Z.min())/(Z.max()-Z.min())
Z[:] = 0.5

texture_id = gl.glGenTextures(1)
gl.glPixelStorei( gl.GL_UNPACK_ALIGNMENT, 1 )
gl.glPixelStorei( gl.GL_PACK_ALIGNMENT, 1 )
gl.glBindTexture( gl.GL_TEXTURE_2D, texture_id )
gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST )
gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST )
gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP )
gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP )
gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_ALPHA,
Z.shape[0], Z.shape[1], 0, gl.GL_ALPHA, gl.GL_FLOAT, Z )
gl.glTexEnvf( gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE )
shader = Shader(vert,frag)
glut.glutMainLoop( )
[font="Helvetica"][/source][/font]

Share this post


Link to post
Share on other sites
Advertisement
Since you didn't specify a precision, glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_ALPHA,
the driver probably decided on GL_ALPHA8 which is a 8 bit integer (0..255)

http://www.opengl.org/wiki/Common_Mistakes#Image_precision

Share this post


Link to post
Share on other sites
Thanks for the hint but it does not work. After further investigation, it seems that my Gaussian function is the responsible for the grid effect as illustrated below:

import matplotlib.pyplot as plt
def gaussian(x):
return np.exp(-2.0 * x * x) * np.sqrt(2.0 / np.pi);
x = np.linspace(0,1,100)
y = gaussian(x+1) + gaussian(x) + gaussian(1-x) + gaussian(2-x)
plt.plot(x,y)
plt.show()




I got the function definition from the anti grain geometry library and I would have thought I was doing the same computation in the shader but obviously I missed a point.

Nicolas

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!