Saturday, December 27, 2014

Python + GLSL 3D Fractal Viewer

Because it's Xmas! 

Pre-requiries: http://pyopengl.sourceforge.net
Source code: https://github.com/cudaopencl/pyRayCaster


Vertex shader

#version 120

varying vec3 normal;
attribute vec2 a_position;
varying vec2 v_position;

void main()
{
   normal = gl_NormalMatrix * gl_Normal;
   gl_Position = vec4(a_position, 0.0, 1.0);
   v_position = a_position;
}

Fragment shader:

#version 120

varying vec2 v_position;
uniform float u_fov = 0.0;
uniform float u_timer = 0.0;
uniform vec3 u_origin = vec3( 0.f, 0.f, -4.f );
uniform float u_rotation_x = 0.0;
uniform float u_rotation_y = 0.0;
uniform float u_rotation_z = 0.0;

vec3 rotate( in vec3 source, in vec3 angles )
{
    vec3 cosAngles = vec3( cos(angles.x), cos(angles.y), cos(angles.z));
    vec3 sinAngles = vec3( sin(angles.x), sin(angles.y), sin(angles.z));

    float x,y,z;
    vec3 returnValue = source;

    // Y axis
    z = source.z*cosAngles.y - source.x*sinAngles.y;
    x = source.z*sinAngles.y + source.x*cosAngles.y;
    returnValue.z = z;
    returnValue.x = x;

    // X axis
    z = returnValue.z*cosAngles.x + returnValue.y*sinAngles.x;
    y = returnValue.z*sinAngles.x - returnValue.y*cosAngles.x;
    returnValue.z = z;
    returnValue.y = y;

    return returnValue;
}

vec4 calc_mandel(vec3 o, vec3 d, float t)
{
   float X = o.x + d.x * t;
   float Y = o.y + d.y * t;
   float Z = o.z + d.z * t;

   vec2 uv = vec2(X*0.2f+0.5f,Y*0.2f+0.5f);
   float scale = 1.f; //512 / 512;
   uv=((uv-0.5)*5.5);
   uv.y*=scale;
   uv.y+=0.0;
   uv.x-=0.5;

   vec2 z = vec2(0.0, 0.0);
   vec3 c = vec3(0.0, 0.0, 0.0);
   float v;

   float I=0.f;
   for(int i=0;(i<100);i++)
   {
      if(((z.x*z.x+z.y*z.y) >= 4.0+cos(u_timer*3.f))) break;
      z = vec2(z.x*z.x - z.y*z.y, 2.0*sin(u_timer*2.6f)*z.y*z.x) + uv;
      if((z.x*z.x+z.y*z.y) >= 2.0)
      {
         c.b=float(i)/20.0;
         c.r=sin((float(i)/5.0));
      }
      I += 1.f+cos(u_timer);
   }
   if(I<Z)
      return vec4(c.b,c.r,0.f,1.0);
   else
      return vec4(0.f,0.f,c.r,0.f);
}

vec4 wave( vec3 o, vec3 d, float t )
{
   float x = o.x + d.x * t;
   float y = o.y + d.y * t;
   float z = o.z + d.z * t;
   float h = cos(x+u_timer)*sin(z);
   if(y<h) {
      float a = 0.2f*(h/(1.f+t*2));
      return vec4(a,a,a,0);
   }
   return vec4(0.f,0.f,0.f,0.f);
}

void main()
{
   vec3 angles = vec3(u_rotation_x,u_rotation_y,u_rotation_z);
    vec2 pos = v_position;
    vec3 origin = u_origin;
    origin.z = u_fov;
    origin = rotate( origin, angles );
    vec3 dir = (vec3(pos.x, pos.y, u_fov+2.f)-origin);
    dir = rotate( dir, angles );

   bool found=false;
   vec4 color = vec4(0.f,0.f,0.f,0.f);
    for( float t=1.f; t<10.f; t+=.5f)
    {
       //color += 5.f*wave(origin, dir, t);
       color += 0.3f*calc_mandel(origin, dir, t);
    }
   gl_FragColor = color;
}

Python code:

 
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import shaders

import sys

SHADER_NAME = 'raycaster'WINDOW_NAME = 'RayCaster'  
 
 
class Application:
    def __init__(self):
        self.geometryRotation = [0.0, 0.0, 0.0]
        self.timer = 0        self.fov = -2.0        self.old = [0.0, 0.0, 0.0]
        self.shader = None        self.origin = [0.0, 0.0, -1.0]

    @staticmethod    def read_shader_from_file(filename):
        file_handle = open(filename, 'r')
        file_content = file_handle.read()
        file_handle.close()
        return file_content

    def mouse(self, button, status, x, y):
        self.old[0] = x
        self.old[1] = y

    def motion(self, x, y):
        #self.fov += (self.old[1] - y) / 500.0        self.geometryRotation[1] -= (self.old[0] - x) / 100.0        self.geometryRotation[0] -= (self.old[1] - y) / 100.0        self.old[0] = x
        self.old[1] = y

    def keyboard(self, key, x, y):
        print key + " pressed"        if key == 'q':
            sys.exit()
        if key == 'r':
            self.compile_shaders()

    def compile_shaders(self):
        print "Initializing shaders"        vertex_shader = shaders.compileShader(
            self.read_shader_from_file(
                'shaders/' + SHADER_NAME + '.vert'), GL_VERTEX_SHADER)
        fragment_shader = shaders.compileShader(
            self.read_shader_from_file(
                'shaders/' + SHADER_NAME + '.frag'), GL_FRAGMENT_SHADER)
        self.shader = shaders.compileProgram(vertex_shader, fragment_shader)
        glUseProgram(self.shader)

    def run(self):
        # self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)        width = 512        height = 512        glutInit(sys.argv)
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
        glutInitWindowSize(width, height)
        glutCreateWindow(WINDOW_NAME)

        glClearColor(0.2, 0.2, 0.2, 1.0)
        glShadeModel(GL_SMOOTH)
        glEnable(GL_CULL_FACE)
        glEnable(GL_DEPTH_TEST)

        glutIdleFunc(self.display)
        glutDisplayFunc(self.display)
        glutMouseFunc(self.mouse)
        glutMotionFunc(self.motion)
        glutKeyboardFunc(self.keyboard)

        glMatrixMode(GL_PROJECTION)
        gluPerspective(45.0, float(width) / float(height), 0.1, 100.0)
        glMatrixMode(GL_MODELVIEW)
        gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0)
        glPushMatrix()

        self.compile_shaders()

        print "Entering main loop..."        glutMainLoop()

    def display(self):

        self.timer += 0.01        loc = glGetUniformLocation(self.shader, 'u_timer')
        glUniform1f(loc, self.timer)
        loc = glGetUniformLocation(self.shader, 'u_rotation_x')
        glUniform1f(loc, self.geometryRotation[0])
        loc = glGetUniformLocation(self.shader, 'u_rotation_y')
        glUniform1f(loc, self.geometryRotation[1])
        loc = glGetUniformLocation(self.shader, 'u_rotation_z')
        glUniform1f(loc, self.geometryRotation[2])

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        color = [1.0, 1.0, 1.0, 1.0]
        glMaterialfv(GL_FRONT, GL_DIFFUSE, color)

        # Draw scene        glPushMatrix()
        size = 1        depth = 0.0        glBegin(GL_QUADS)
        glVertex3f(-size, -size, depth)
        glNormal3f(0.0, 0.0, -1.0)
        glVertex3f(size, -size, depth)
        glNormal3f(0.0, 0.0, -1.0)
        glVertex3f(size, size, depth)
        glNormal3f(0.0, 0.0, -1.0)
        glVertex3f(-size, size, depth)
        glNormal3f(0.0, 0.0, -1.0)
        glEnd()

        glPopMatrix()
        glutSwapBuffers()

if __name__ == '__main__':
    app = Application()
    app.run()

Tuesday, August 26, 2014

Photo exhibition

Working on photo exhibition based on my work on ray-tracing. Generating ultra definition pictures on good old GTX 480.

Thursday, May 1, 2014

Material Editor for SoL-R

After a few interop issues between the GUI and the GPU library (CUDA and OpenCL), I finally got it working! The GUI makes it simple to manipulate materials on the fly, and validate texture mapping implementation (Bump, Normal, Specular, etc).





Saturday, January 4, 2014

Sketchup plugin in progress...

Never more than a second to produce the following screenshots in 800x600.