Tuesday, March 1, 2011

PyOpenGL Geometry Shaders - Python and OpenGL Geometry Shader

Geometry Shaders using PyOpenGL - Implementation



Extending our shader from a previous post, Using GLSL in Python PyOpenGL we can simply add geometry shaders if your video card supports such a beast.



Geometry Shader Class in Python



The following is a shader class written in Python. Its based on our previous shader class except weve made some additions to support Geometry Shaders. We will start with the includes




from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL.ARB.framebuffer_object import *
from OpenGL.GL.EXT.framebuffer_object import *
from OpenGL.GL.ARB.vertex_buffer_object import *
from OpenGL.GL.ARB.geometry_shader4 import *
from OpenGL.GL.EXT.geometry_shader4 import *


Not sure how many of these are actually used in this class, but they are there in case. The file contains other opengl related classes so they are there. Next I will show the class itself




class shader(node) :
def __init__(self, filename):
node.__init__(self)
self.filename = filename
self.load()

def load(self, debug=False):
fh = open(self.filename)
self.source = {'vertex': '', 'fragment':'', 'geometry':''}
write = None
for line in fh :
if line == '[[vertex-program]]\n' :
write = 'vertex'
elif line == '[[fragment-program]]\n' :
write = 'fragment'
elif line == '[[geometry-program]]\n' :
write = 'geometry'
else :
self.source[write] += line

self.draw = self.init
if debug :
print self.source['vertex']
print self.source['fragment']
print self.source['geometry']



def init(self):
##compile and link shader
self.vs = self.fs = self.gs = 0

self.vs = glCreateShader(GL_VERTEX_SHADER)
self.fs = glCreateShader(GL_FRAGMENT_SHADER)
self.gs = glCreateShader(GL_GEOMETRY_SHADER_EXT)

glShaderSource(self.vs, self.source['vertex'])
glShaderSource(self.fs, self.source['fragment'])
glShaderSource(self.gs, self.source['geometry'])

glCompileShader(self.vs)
log = glGetShaderInfoLog(self.vs)
if log: print 'Vertex Shader: ', log

glCompileShader(self.gs)
log = glGetShaderInfoLog(self.gs)
if log: print 'Geometry Shader: ', log

glCompileShader(self.fs)
log = glGetShaderInfoLog(self.fs)
if log: print 'Fragment Shader: ', log

self.prog = glCreateProgram()

glAttachShader(self.prog, self.vs)
glAttachShader(self.prog, self.fs)
glAttachShader(self.prog, self.gs)

glLinkProgram(self.prog)

glUseProgram(self.prog)

self.draw = self.use

def use(self):
glUseProgram(self.prog)
uniform_location = glGetUniformLocation(self.prog, "time")
glUniform1i(uniform_location, pygame.time.get_ticks())

def end(self):
glUseProgram(0)


Explaination of OpenGL Geometry Shader GL_GEOMETRY_SHADER_EXT



First difference is in the shader.load function. We have added code to load the actual source code for the shader. Secondly we create the shader with:



self.gs = glCreateShader(GL_GEOMETRY_SHADER_EXT)


GL_GEOMETRY_SHADER_EXT seems to be the only one defined for me. We contine normally now. The main additions are to the shader source code.



OpenGL Geometry Shader source code



Each section of the code is marked by delimters [[vertex-program]], [[fragment-program]], and [[geometry-program]]. Below is the source code




[[vertex-program]]
uniform int time;

void main(void) {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

[[geometry-program]]
#version 150
#extension GL_EXT_geometry_shader4 : enable

layout(triangles) in;
layout(line_strip, max_vertices = 20) out;

void emit(vec4 vertex) {
gl_Position = vertex;
EmitVertex();
}

void main(void) {
vec4 avg = vec4(0., 0., 0., 0.);
int i;
for(i=0; i< gl_VerticesIn; i++){
avg += gl_PositionIn[i];
}
avg /= (gl_VerticesIn * 1.0);

vec4 mid1 = (gl_PositionIn[0] + gl_PositionIn[1]) / 2.0;
vec4 mid2 = (gl_PositionIn[1] + gl_PositionIn[2]) / 2.0;
vec4 mid3 = (gl_PositionIn[2] + gl_PositionIn[0]) / 2.0;

emit(gl_PositionIn[0]);
emit(mid1);
emit(mid3);
emit(mid2);
emit(mid1);
emit(gl_PositionIn[1]);
emit(mid2);
emit(gl_PositionIn[2]);
emit(mid3);
emit(gl_PositionIn[0]);

EndPrimitive();
}


[[fragment-program]]
uniform sampler2D texture_0;

void main (void) {
vec4 cvec = texture2D(texture_0, gl_TexCoord[0].xy);
gl_FragColor = cvec;
gl_FragColor.a = 1.0;
}


Caveats with OpenGL Geometry Program, it always uses triangles



Something that took me awhile to figure out is that the geometry shader always works in triangles. I couldn't figure out why quads was not defined in GLSL. I was using GL_QUADS so I naturally figured it would exist. It does not. Internal OpenGL pipeline converts to triangles here. Maybe this is common knowledge, maybe it is not. Someone can feel free to correct me.



Other interesting things are the extra lines there




#version 150
#extension GL_EXT_geometry_shader4 : enable

layout(triangles) in;
layout(line_strip, max_vertices = 20) out;


The top comments are required for me. The first function layout() show the input, triangles as mentioned earlier. The next specifies output, which is line strip. I did this to show the effect of the shader, it will draw line strips instead of triangle_strip which would make more sense in the real world perhaps.

Friday, November 19, 2010

Faster and More Responsive Desktop in Linux

Faster Linux Desktop - Changing the scheduling paradigm to increase responsiveness for desktop useage



Came across an interesting article about speeding up the desktop usage in linux by altering the threading and process scheduling algorithm.

More details can be found here : http://blogs.computerworld.com/17371/the_linux_desktop_may_soon_be_a_lot_faster

My question is would this change performance for servers that have no graphical user interface running IE xorg? It looks like it won't!

Postgres unable to start with shmget. SHMMAX too small

Error Starting PostgreSQL, Could not create shared memory segment errors



If you have a large PostgreSQL configuration that supports many concurrent requests, you may find yourself starting it as you have increased the shared_buffers parameter or max_connections parameter, and it fails to start.

The error message will say something like could not create shared memory segment, Failed system call was shmget. This error usually means that PostgreSQL's request for a shared memory segment exceeded your kernel's SHMMAX parameter. You can either reduce the request size or reconfigure the kernel with larger SHMMAX. SHMMAX too small.

Here is the exact error message I got:


debian-testing:~# /etc/init.d/postgresql-8.3 start
Starting PostgreSQL 8.3 database server: mainThe PostgreSQL server failed to start. Please check the log output: 2010-11-17 13:53:34 EST FATAL: could not create shared memory segment: Invalid argument 2010-11-17 13:53:34 EST DETAIL: Failed system call was shmget(key=5432001, size=147382272, 03600). 2010-11-17 13:53:34 EST HINT: This error usually means that PostgreSQL's request for a shared memory segment exceeded your kernel's SHMMAX parameter. You can either reduce the request size or reconfigure the kernel with larger SHMMAX. To reduce the request size (currently 147382272 bytes), reduce PostgreSQL's shared_buffers parameter (currently 16384) and/or its max_connections parameter (currently 503). If the request size is already small, it's possible that it is less than your kernel's SHMMIN parameter, in which case raising the request size or reconfiguring SHMMIN is called for. The PostgreSQL documentation contains more information about shared memory configuration. failed!
failed!


PostgreSQL Debian increase SHMMAX



In order to increase the maximum amount of shared memory a linux program can access, we need to adjust kernel parameters. Since we are using Debian they are available in /etc/sysctl.conf. This should be similar for many linux distributions.

We simple edit this file:

sudo vim /etc/sysctl.conf


or if you have GNOME running

sudo gedit /etc/sysctl.conf


And either search for the line or add the line (most likely will have to add) :


kernel.shmmax = 147382272


Note the number here is the same as "size" in this system call, shown in my error message above: shmget(key=5432001, size=147382272, 03600)

Now we have to put these settings into effect by running the command


sysctl -p


And now we start PostgreSQL up without the error:


debian-testing:~# /etc/init.d/postgresql-8.3 start
Starting PostgreSQL 8.3 database server: main.
debian-testing:~#

Thursday, November 18, 2010

Intel OpenCV Open Source Computer Vision Software

Face Tracking, Motion Tracking, OpenCV - Free Computer Vision Library



Was looking into how to do face tracking and possibly motion tracking. With face tracking I was hoping I could find a way to track facial expressions, ie the eyebrow position, mouth position, as is done with many CG characters nowadays. OpenCV is an open library by Intel that allows you to carry out various computer vision tasks. Facial tracking is one of the demos that comes with OpenCV.

How OpenCV's facial tracking works can be described in great detail


You can find out more about how OpenCV's facial tracking works here : http://www.cognotics.com/opencv/servo_2007_series/part_3/sidebar.html


Check out Intel's OpenCV library - computer vision


Check out the a wiki for more detailed information here : http://opencv.willowgarage.com/wiki/

Face Tracking OpenCV - Cool demo on youtube


http://www.youtube.com/watch?v=AUhFjG-WSPE

Tuesday, November 16, 2010

Mozilla's HTML 5 Audio API Draft

HTML 5 - Mozilla's Draft for the Audio API


Defining an Enhanced API for Audio (Draft Recommendation) by Mozilla



Was looking into writing a html 5 script that can generate tones given a frequency (ie 440 hz for 'A') . Alas, it seems out of my reach for now as Mozillas Audio Writing API does not appear to work in my version of firefox. Cmon people lets get moving!

https://wiki.mozilla.org/Audio_Data_API

Cool Examples



Toy Piano
Javascript text-to-speech engine

Let me know if any of these work for you, because they don' work for me :(

Monday, November 8, 2010

Site Launch

Sheet-Music-Tabs.com



New site has been launched. Lets watch the SEO value... lots of competition out there



Sheet-Music-Tabs.com

New! Speed of Flow tabs by The Rodeo Carburettor

Monday, September 13, 2010

Load Balancing Web Servers using ldirectord

Web Server Load Balancing



Summary



Using ldirectord to set up load balancing in apache, using debian linux as my distro, should also work on ubuntu or any other distro for that matter (bsd, red hat, etc). See below for links to the documentation. This setup is done using ldirectord's masq mode, which is basically ip masquerading function using iptables.

Let's Begin



Im just going to take a few mins to explain my load balancing set up. What we have is 1 router, the default gateway, connected to the internet, and also connecting to an internal network. Standard set up really.

What we want to do is set up load balancing with 2 (or more, our case we have 4) apache servers.

First step - download ldirectord



http://horms.net/projects/ldirectord/ (ldirectord) is a daemon that will route traffic to a certain host based on whatever load balancing algorithm you choose. Some examples of algorithms are round robin, where it selects the next host every time, or least connections, route to the host with the least number of open connections. There are a few other options that are covered in the ldirectord documentation (man page) and specifically for the algorithms is in the IPVSADM man page under -s (scheduler) located here (http://linux.die.net/man/8/ipvsadm)

Note that ldirectord is now a sub project of linux HA project called Heartbeat. It is available as a part of that package available here http://www.linux-ha.org/wiki/Main_Page

The reason for this is ldirectord is used as a part of that package. It is also useable on its own as I will show you.

Ldirectord set up



What we have to do next is set up ldirectord after we manage to get it compiled. Here is an example of a /etc/ha.d/ldirectord.cf:


# Global Directives
checktimeout=10
checkinterval=2
autoreload=no
logfile="local0"
quiescent=yes

# Virtual Server for HTTP
virtual=10.1.1.10:80
real=10.1.1.21:80 masq
real=10.1.1.22:80 masq
real=10.1.1.23:80 masq
real=10.1.1.12:80 masq
service=http
request="ldirectord.html"
receive="Test Page"
scheduler=wlc
protocol=tcp
checktype=negotiate


As you can see, we have set this ldirectord program up on the host located at 10.1.1.10 which is a physical machine. Using Heartbeat you can set up a virtual IP address and have 2 or more machines take over that address when the main one goes down, but that is for another article. We are strictly focusing on setting up ldirectord here.

Setting up the load balanced machines



On each of the load balanced machines (10.1.1.21, 22, 23, and 12) we need to set the default gateway to 10.1.1.10 (the ip address of the load balancer) Please adjust accordingly to your network. This can be done using the following command on debian linux and most other types

route add default gw 10.1.1.10


Next we have set up our ldirectord to check each machine by loading the page "ldirectord.html" shown above. So really it will be trying to access the page http://10.1.1.21/ldirectord.html. We have set up a regular expression as well above saying "Test Page". As long as this url returns this string somewhere, the host will be considered "up" by ldirectord. After we have set everything up, it should be good to go.

Running ldirectord



Please make sure your config file is in /etc/ha.d/ldirectord.cf because the script will be searching there for it. Next run ldirectord by typing

/usr/bin/perl /usr/sbin/ldirectord start


You should make a init.d script for this. After you have run ldirectord, typing

ipvsadm -L


should give you some information on its status.


s5:/etc/ha.d# ipvsadm -L
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP s5.np.local:www wlc
-> s4.np.local:www Masq 1 6 2245
-> s7.np.local:www Masq 1 5 2275
-> s3.np.local:www Masq 1 4 2563
-> s9.np.local:www Masq 1 6 2074


Here it shows that all hosts are up (their "Weight" is each 1) and have active connections running to them.

Setting up external routing



Now just have your router point all web traffic to 10.1.1.10:80 and you should have full load balancing. Note there are other problems such as how are you going to make sure they are all synchronized. You can use tools such as rsync, or use NFS to mount a share that contains all your files on each of the slave servers (our approach). The NFS approach seems to work nicely, however if you are hosting webservers for file transfers it may become a bottleneck so make sure your internet network is fast (1000 mbit) and tweaking NFS settings to your liking.

Thank you, your comments are welcome!