Exemple #1
0
 def OnInit(self):
     """Load the image on initial load of the application"""
     print """Should see a rotating star-field"""
     starfield = random.rand(9110, 3)
     self.coordinate = Coordinate(point=starfield, )
     self.color = Color(color=starfield, )
     self.transform = Transform(
         scale=(200, 200, 200),
         children=[
             Transform(
                 translation=(-.5, -.5, -.5),
                 children=[
                     Shape(geometry=PointSet(
                         coord=self.coordinate,
                         color=self.color,
                     ), ),
                 ],
             ),
         ],
     )
     self.sg = sceneGraph(children=[
         self.transform,
     ], )
     self.time = Timer(duration=90.0, repeating=1)
     self.time.addEventHandler("fraction", self.OnTimerFraction)
     self.time.register(self)
     self.time.start()
Exemple #2
0
 def OnInit( self ):
     self.sg = scene
     self.addEventHandler( "keypress", name="a", function = self.OnAdd)
     self.time = Timer( duration = .1, repeating = 1 )
     self.time.addEventHandler( "cycle", self.OnAdd )
     self.time.register (self)
     self.time.start ()
 def OnInit( self ):
     self.sg = basenodes.sceneGraph(
         children = [
             basenodes.Transform(
                 children = [
                     basenodes.Shape(
                         geometry = basenodes.Box(
                             size = (2,3,4),
                         ),
                         appearance=basenodes.Appearance(
                             material = basenodes.Material(
                                 diffuseColor = (1,0,0),
                             ),
                         ),
                     ),
                 ],
             ),
             basenodes.PointLight(
                 location=(5,6,5),
             ),
         ],
     )
     self.time = Timer( duration = 32.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
     self.rotation =  0
Exemple #4
0
 def OnInit(self):
     """Initialize the context with GL active"""
     if not glInitShadowARB() or not glInitDepthTextureARB():
         print 'Missing required extensions!'
         sys.exit(testingcontext.REQUIRED_EXTENSION_MISSING)
     '''Configure some parameters to make for nice shadows
     at the expense of some extra calculations'''
     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
     glEnable(GL_POLYGON_SMOOTH)
     '''We create the geometry for our scene in a method to allow
     later tutorials to subclass and provide more interesting scenes.
     '''
     self.geometry = self.createGeometry()
     '''We'll use OpenGLContext's rendering passes to render the geometry 
     each time we need to do so...'''
     self.geometryPasses = flat.FlatPass(self.geometry, self)
     '''To make the demo a little more interesting, we're going to
     animate the first light's position and direction.  Here we're setting
     up a raw Timer object.  OpenGLContext scenegraph timers can't be used
     as we're not using the scenegraph mechanisms.
     '''
     self.time = Timer(duration=8.0, repeating=1)
     self.time.addEventHandler("fraction", self.OnTimerFraction)
     self.time.register(self)
     self.time.start()
     '''Here are the lights we're going to use to cast shadows.'''
     self.lights = self.createLights()
     self.addEventHandler("keypress", name="s", function=self.OnToggleTimer)
Exemple #5
0
    def OnInit(self):
        """Load the image on initial load of the application"""
        self.image = self.loadImage()
        print("""You should see a slowly rotating textured cube

The animation is provided by a timer, rather than the
crude time-module based animation we use for the other
NeHe tutorials.""")
        print('  <r> reverse the time-sequence')
        print('  <s> make time pass more slowly')
        print('  <f> make time pass faster')
        '''Here we will register key-press handlers for the various 
        operations the user can perform.'''
        self.addEventHandler("keypress", name="r", function=self.OnReverse)
        self.addEventHandler("keypress", name="s", function=self.OnSlower)
        self.addEventHandler("keypress", name="f", function=self.OnFaster)
        '''We'll create a Timer object.  The duration is the total 
        cycle length for the timer, the repeating flag tells the 
        timer to continue running.'''
        self.time = Timer(duration=8.0, repeating=1)
        '''The timer generates events for "fractions" as well as for 
        cycles.  We use the fraction value to generate a smooth 
        animation.'''
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        '''Registering and starting the timer are only necessary because
        the node is not part of a scenegraph.'''
        self.time.register(self)
        self.time.start()
        '''As with the time.time() mechanism, we need to track our 
        current rotation so that the rendering pass can perform the 
        rotation calculated by the timer callback.'''
        self.rotation = 0
Exemple #6
0
 def OnInit(self):
     self.sg = scene
     self.trans = self.sg.children[0]
     self.time = Timer(duration=8.0, repeating=1)
     self.time.addEventHandler("fraction", self.OnTimerFraction)
     self.time.register(self)
     self.time.start()
Exemple #7
0
    def OnInit(self, ):
        """Initialisation"""
        print("""You should see two bitmap images traversing the screen
    diagonally.  If the GL.ARB.window_pos extension is not available
    then you will exit immediately.
    """)
        self.width, self.height, self.data = self.loadImage()
        global window_pos
        window_pos = self.extensions.initExtension("GL.ARB.window_pos")
        if not window_pos:
            print('GL_ARB_window_pos not supported!')
            sys.exit(testingcontext.REQUIRED_EXTENSION_MISSING)
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.x = 0
        self.y = 0

        try:
            window_pos.glWindowPos2dvARB(())
        except (error.CopyError, GLerror, ValueError) as err:
            print('Correct handling of incorrect parameters', err)
        except Exception as err:
            traceback.print_exc()
            print('Incorrect handling of incorrect parameters')
        try:
            window_pos.glWindowPos3dvARB(())
        except (error.CopyError, GLerror, ValueError) as err:
            print('Correct handling of incorrect parameters', err)
        except Exception as err:
            traceback.print_exc()
            print('Incorrect handling of incorrect parameters')
Exemple #8
0
 def OnInit( self ):
     """Load the image on initial load of the application"""
     print("""Should see a sine wave fading from green to red""")
     line = arange(0.0,1.0,.01)
     line2 = line[::-1]
     self.coordinate = Coordinate(
         point = map(None, line,[0]*len(line), [0]*len(line) ),
     )
     self.color = Color(
         color = map(None,line, [0]*len(line), line2 ),
     )
     self.sg = sceneGraph(
         children = [
             Transform(
                 translation = (-.5,0,0),
                 children = [
                     Shape(
                         geometry = PointSet(
                             coord = self.coordinate,
                             color = self.color,
                         ),
                     ),
                 ],
             ),
         ],
     )
     self.time = Timer( duration = 8.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
Exemple #9
0
class TestContext(wxinteractivecontext.wxInteractiveContext):
    rotating = 1

    def OnInit(self):
        self.sg = basenodes.sceneGraph(children=[
            basenodes.Transform(children=[
                basenodes.Shape(
                    geometry=basenodes.Box(size=(2, 3, 4), ),
                    appearance=basenodes.Appearance(
                        material=basenodes.Material(diffuseColor=(1, 0,
                                                                  0), ), ),
                ),
            ], ),
            basenodes.PointLight(location=(5, 6, 5), ),
        ], )
        self.time = Timer(duration=32.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.rotation = 0

    def OnTimerFraction(self, event):
        """Update our rotation from the timer event"""
        self.sg.children[0].rotation = (0, 1, 0,
                                        event.fraction() * 3.14149 * 2)

    def OnButtonPause(self, event):
        """Handle the wxPython event from our button"""
        if self.rotating:
            self.time.pause()
        else:
            self.time.resume()
        self.rotating = not self.rotating
Exemple #10
0
    def OnInit(self):
        vshader = '''
        //setup a tween (blending constant)
        uniform float tween;
        // the the original position
        // and the secondary position (tweened)
        attribute vec3 position;
        attribute vec3 tweened;
        attribute vec3 color;
        varying vec4 baseColor;

        void main(){
            // create a new position for this vertex
            // by mixing the original position and the
            // secondary tweened position
            gl_Position = gl_ModelViewProjectionMatrix * mix(
                vec4(position, 1.0),
                vec4(tweened, 1.0),
                tween
            );
            baseColor = vec4(color, 1.0);
        }
        '''
        vertex = shaders.compileShader(vshader, GL_VERTEX_SHADER)
        fshader = '''
        varying vec4 baseColor;
        void main(){
            gl_FragColor = baseColor;
        }
        '''
        fragment = shaders.compileShader(fshader, GL_FRAGMENT_SHADER)
        self.shader = shaders.compileProgram(vertex, fragment)

        # create a vbo with vertex position, color, and secondary position
        self.vbo = vbo.VBO(
            array([
                [0, 1, 0, 1, 3, 0, 0, 1, 0],
                [-1, -1, 0, -1, -1, 0, 1, 1, 0],
                [1, -1, 0, 1, -1, 0, 0, 1, 1],
                [2, -1, 0, 2, -1, 0, 1, 0, 0],
                [4, -1, 0, 4, -1, 0, 0, 1, 0],
                [4, 1, 0, 4, 9, 0, 0, 0, 1],
                [2, -1, 0, 2, -1, 0, 1, 0, 0],
                [4, 1, 0, 1, 3, 0, 0, 0, 1],
                [2, 1, 0, 1, -1, 0, 0, 1, 1],
            ], 'f'))
        # get the memory locations in our shader
        # for our variables
        self.position_location = glGetAttribLocation(self.shader, 'position')
        self.tweened_location = glGetAttribLocation(self.shader, 'tweened')
        self.color_location = glGetAttribLocation(self.shader, 'color')
        self.tween_location = glGetUniformLocation(self.shader, 'tween')

        # setup an animation timer which updates the
        # tween fraction (called tween in our shader)
        self.time = Timer(duration=2.0, repeating=1)
        self.time.addEventHandler('fraction', self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
    def OnInit(self):
        """Do all of our setup functions..."""
        if not glMultiTexCoord2f:
            print('Multitexture not supported!')
            sys.exit(1)

        self.update_sim = False
        vBuffer, uvBuffer, nBuffer, tBuffer, bBuffer, cBuffer, iBuffer, triangles = \
            loadMesh("TestMesh.obj", True, 0.001)

        self.indices = iBuffer
        self.vertices = vBuffer
        self.tex_coords = uvBuffer
        self.normals = nBuffer
        self.tangents = tBuffer
        self.biTangents = bBuffer
        self.colors = cBuffer

        normal_array = rasterizer.raster_vector_attrib(self.normals, self.tex_coords,\
                    triangles, SIM_SIZE, SIM_SIZE, UP)
        tangent_array = rasterizer.raster_vector_attrib(self.tangents, self.tex_coords,\
                    triangles, SIM_SIZE, SIM_SIZE, X_DIR)
        biTangent_array = rasterizer.raster_vector_attrib(self.biTangents, self.tex_coords,\
                    triangles, SIM_SIZE, SIM_SIZE, Y_DIR)

        self.fluid_sim = FluidSim.Fluid_Sim_2D(SIM_SIZE, SIM_SIZE, CELL_SIZE, DENSITY, GRAVITY,\
                    ATM_PRESSURE)
        for r in range(SIM_SIZE):
            for c in range(SIM_SIZE):
                self.fluid_sim.setNormal(r, c, normal_array[r][c])
                self.fluid_sim.setXTangent(r, c, tangent_array[r][c])
                self.fluid_sim.setYTangent(r, c, biTangent_array[r][c])

        sources = []
        for rc in INJECT_POINTS:
            for dr in range(-INJECT_RADIUS / 2, INJECT_RADIUS / 2 + 1):
                for dc in range(-INJECT_RADIUS / 2, INJECT_RADIUS / 2 + 1):
                    if dr * dr + dc * dc <= INJECT_RADIUS * INJECT_RADIUS:
                        sources.append((rc[0] + dr, rc[1] + dc))
        self.fluid_sim.markSources(sources)

        self.addEventHandler("keypress", name="r", function=self.OnReverse)
        self.addEventHandler("keypress", name="s", function=self.OnSlower)
        self.addEventHandler("keypress", name="f", function=self.OnFaster)
        self.addEventHandler("keypress", name="w", function=self.incPhi)
        self.addEventHandler("keypress", name="s", function=self.decPhi)
        self.addEventHandler("keypress", name="d", function=self.incTheta)
        self.addEventHandler("keypress", name="a", function=self.decTheta)
        self.addEventHandler("keypress", name="u", function=self.promptUpdate)
        print('r -- reverse time\ns -- slow time\nf -- speed time')
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        '''Load both of our textures.'''
        self.Load()

        self.frameCount = 0
Exemple #12
0
	def OnInit( self ):
		vertex = shaders.compileShader("""
			uniform float tween;
			attribute vec3 position;
			attribute vec3 tweened;
			attribute vec3 color;
			varying vec4 baseColor;
			void main() {
				gl_Position = gl_ModelViewProjectionMatrix * mix(
					vec4( position,1.0),
					vec4( tweened,1.0),
					tween
				);
				baseColor = vec4(color,1.0);
			}""",GL_VERTEX_SHADER)
		fragment = shaders.compileShader("""
			varying vec4 baseColor;
			void main() {
				gl_FragColor = baseColor;
			}""",GL_FRAGMENT_SHADER)
		self.shader = shaders.compileProgram(vertex,fragment)
		self.vbo = vbo.VBO(
			array( [
				#depan
				[  1, 3, 1, 0.5, 3, 1.5,  0,1,0 ],
				[  -1, 3, 1, 0.5, 3, 0.5,  0,1,0 ],
				[  1, -3, 1, 0.5, -3, 1.5,  0,1,0 ],
				[  -1, 3, 1, 0.5, 3, 0.5,  0,1,0 ],
				[  -1, -3, 1, 0.5, -3, 1.5,  0,1,0 ],
				[  1, -3, 1, 0.5, -3, 1.5,  0,1,0 ],

				#depan
				[  1, 3, -2, 0.5, 3, -1.5,  1,1,0 ],
				[  -1, 3, -2, 0.5, 3, -2.5,  1,1,0 ],
				[  1, -3, -2, 0.5, -3, -1.5,  1,1,0 ],
				[  -1, 3, -2, 0.5, 3, -2.5,  1,1,0 ],
				[  -1, -3, -2, 0.5, -3, -1.5,  1,1,0 ],
				[  1, -3, -2, 0.5, -3, -1.5,  1,1,0 ],
			],'f')
		)
		self.position_location = glGetAttribLocation(
			self.shader, 'position'
		)
		self.tweened_location = glGetAttribLocation(
			self.shader, 'tweened',
		)
		self.color_location = glGetAttribLocation(
			self.shader, 'color'
		)
		self.tween_location = glGetUniformLocation(
			self.shader, 'tween',
		)
		self.time = Timer( duration = 2.0, repeating = 1 )
		self.time.addEventHandler( "fraction", self.OnTimerFraction )
		self.time.register (self)
		self.time.start ()
Exemple #13
0
    def OnInit(self):
        """Load the image on initial load of the application"""
        print """This demo loads a VRML97 scenegraph and modifies
the rotation of the transform which contains one of the two boxes.
The ROUTE in the scene transmits this rotational change to the
transform which contains the other box."""
        self.sg = Loader.load(os.path.join("wrls", "box.wrl"))
        self.trans = self.sg.getDEF("Box01")
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
 def OnInit( self ):
     """Load the image on initial load of the application"""
     print """Should see a sine wave fading from green to red"""
     line = arange(0.0,1.0,.01)
     line2 = line[::-1]
     self.coordinate = Coordinate(
         point = map(None, line,[0]*len(line), [0]*len(line) ),
     )
     self.color = Color(
         color = map(None,line, [0]*len(line), line2 ),
     )
     self.sg = sceneGraph(
         children = [
             Transform(
                 translation = (-.5,0,0),
                 children = [
                     Shape(
                         geometry = PointSet(
                             coord = self.coordinate,
                             color = self.color,
                         ),
                     ),
                 ],
             ),
         ],
     )
     self.time = Timer( duration = 8.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
Exemple #15
0
 def OnInit( self ):
     """Load the image on initial load of the application"""
     print """Should see a rotating star-field"""
     starfield = random.rand( 9110, 3 )
     self.coordinate = Coordinate(
         point = starfield,
     )
     self.color = Color(
         color = starfield,
     )
     self.transform = Transform(
         scale = (200,200,200),
         children = [
             Transform(
                 translation=(-.5,-.5,-.5),
                 children=[
                     Shape(
                         geometry = PointSet(
                             coord = self.coordinate,
                             color = self.color,
                         ),
                     ),
                 ],
             ),
         ],
     )
     self.sg = sceneGraph(
         children = [
             self.transform,
         ],
     )
     self.time = Timer( duration = 90.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
Exemple #16
0
 def OnInit( self ):
     """Initialize the context with GL active"""
     if not glInitShadowARB() or not glInitDepthTextureARB():
         print 'Missing required extensions!'
         sys.exit( testingcontext.REQUIRED_EXTENSION_MISSING )
     '''Configure some parameters to make for nice shadows
     at the expense of some extra calculations'''
     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
     glEnable( GL_POLYGON_SMOOTH )
     '''We create the geometry for our scene in a method to allow
     later tutorials to subclass and provide more interesting scenes.
     '''
     self.geometry = self.createGeometry()
     '''We'll use OpenGLContext's rendering passes to render the geometry 
     each time we need to do so...'''
     self.geometryPasses = flat.FlatPass(self.geometry,self)
     '''To make the demo a little more interesting, we're going to
     animate the first light's position and direction.  Here we're setting
     up a raw Timer object.  OpenGLContext scenegraph timers can't be used
     as we're not using the scenegraph mechanisms.
     '''
     self.time = Timer( duration = 8.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
     '''Here are the lights we're going to use to cast shadows.'''
     self.lights = self.createLights()
     self.addEventHandler( "keypress", name="s", function = self.OnToggleTimer)
 def OnInit( self ):
     self.sg = basenodes.sceneGraph(
         children = [
             basenodes.Transform(
                 children = [
                     basenodes.Shape(
                         geometry = basenodes.Box(
                             size = (2,3,4),
                         ),
                         appearance=basenodes.Appearance(
                             material = basenodes.Material(
                                 diffuseColor = (1,0,0),
                             ),
                         ),
                     ),
                 ],
             ),
             basenodes.PointLight(
                 location=(5,6,5),
             ),
         ],
     )
     self.time = Timer( duration = 32.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
     self.rotation =  0
    def OnInit(self):
        self.angle = 0

        shader_common = read_shader(
            'shader_common.h', D={'NLIGHTS': len(self.get_lights())})

        phong_weightCalc = read_shader('phong_weightCalc.h')
        phong_preCalc = read_shader('phong_preCalc.h')

        light_preCalc = read_shader('light_preCalc.h')

        self.shader = Shader.compile(
            shader_common + phong_preCalc + light_preCalc +
            read_shader('vertex.h'),
            shader_common + phong_weightCalc +
            read_shader('fragment.h'))

        self.time = Timer(duration=20.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()

        self.set_terrain_ttd()

        self.vw = self.vh = 300
Exemple #19
0
    def OnInit(self):
        """Do all of our setup functions..."""
        if not glMultiTexCoord2f:
            print('Multitexture not supported!')
            sys.exit(1)

        self.addEventHandler("keypress", name="r", function=self.OnReverse)
        self.addEventHandler("keypress", name="s", function=self.OnSlower)
        self.addEventHandler("keypress", name="f", function=self.OnFaster)
        print('r -- reverse time\ns -- slow time\nf -- speed time')
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        '''Load both of our textures.'''
        self.Load()
Exemple #20
0
class TestContext( BaseContext ):
    '''
    creates a simple vertex shader
    '''
    def OnInit( self ):
        try:
            self.shader = compileProgram(
                compileShader( VERTEX_SHADER, gl.GL_VERTEX_SHADER ),
                compileShader( FRAGMENT_SHADER, gl.GL_FRAGMENT_SHADER )
            )
        except RuntimeError, err:
            sys.stderr.write( err.args[0] )
            sys.exit( 1 )

        self.vbo = vbo.VBO(
            array( VERTEX_DATA, 'f' )
        )

        self.position = gl.glGetAttribLocation( self.shader, 'position' )
        self.tweened = gl.glGetAttribLocation( self.shader, 'tweened' )
        self.color = gl.glGetAttribLocation( self.shader, 'color' )
        self.tween = gl.glGetUniformLocation( self.shader, 'tween' )

        self.time = Timer( duration = 2.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register( self )
        self.time.start()
 def OnInit( self ):
     """Load the image on initial load of the application"""
     haveExtension = self.extensions.initExtension( "GL.ARB.point_parameters")
     if not haveExtension:
         print('GL_ARB_point_parameters not supported!')
         sys.exit( testingcontext.REQUIRED_EXTENSION_MISSING )
     print("""Should see a sine wave overhead""")
     print('press x toggle use of the extension')
     self.addEventHandler(
         'keypress', name = 'x', function = self.OnDisableExtension
     )
     
     line = arange(0.0,1.0,.01)
     line2 = line[::-1]
     self.coordinate = Coordinate(
         point = zip(line,[0]*len(line), [0]*len(line) ),
     )
     self.color = Color(
         color = zip(line, [0]*len(line), line2 ),
     )
     self.geometry = PointSet(
         coord = self.coordinate,
         color = self.color,
         size = 4.0,
         minSize = 0.25,
         maxSize = 4.0,
         attenuation = (0,0,1),
     )
     self.sg = sceneGraph(
         children = [
             Transform(
                 translation = (-.5,.25,0),
                 scale = (2,2,2),
                 rotation = (1,0,0,1.57),
                 children = [
                     Shape(
                         geometry = self.geometry,
                     ),
                 ],
             ),
         ],
     )
     self.time = Timer( duration = 8.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
Exemple #22
0
	def OnInit(self):
		"""initialize the context"""
		vertex = shaders.compileShader("""
			uniform float tween;
            attribute vec3 position;
            attribute vec3 tweened;
            attribute vec3 color;
            varying vec4 baseColor;
            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * mix(
                    vec4( position,1.0),
                    vec4( tweened,1.0),
                    tween
				);

			baseColor = vec4(color,1.0);

			}""",GL_VERTEX_SHADER)
		
		fragment = shaders.compileShader("""
			varying vec4 baseColor;
			void main(){
			gl_FragColor = baseColor;
			}""",GL_FRAGMENT_SHADER)
		self.shader = shaders.compileProgram(vertex,fragment)

		self.vbo = vbo.VBO(
            array( [
                [  0, 1, 0, 1,3,0,  0,1,0 ],
                [ -1,-1, 0, -1,-1,0,  1,1,0 ],
                [  1,-1, 0, 1,-1,0, 0,1,1 ],
                [  2,-1, 0, 2,-1,0, 1,0,0 ],
                [  4,-1, 0, 4,-1,0, 0,1,0 ],
                [  4, 1, 0, 4,9,0, 0,0,1 ],
                [  2,-1, 0, 2,-1,0, 1,0,0 ],
                [  4, 1, 0, 1,3,0, 0,0,1 ],
                [  2, 1, 0, 1,-1,0, 0,1,1 ],
            ],'f')
        )

		self.position_location = glGetAttribLocation(
        	self.shader,'position'
        	)
		self.tweened_location = glGetAttribLocation(
        	self.shader,'tweened'
        	)
		self.color_location = glGetAttribLocation(
        	self.shader,'color'
        	)
		self.tween_location = glGetUniformLocation(
        	self.shader,'tween'
        	)

		self.time = Timer (duration = 2.0, repeating = 1)
		self.time.addEventHandler( "fraction",self.OnTimerFraction)
		self.time.register (self)
		self.time.start ()
Exemple #23
0
    def OnInit(self):

        self.is_trans = True
        self.vertex_shaders = [st.ANIMATED_VERTEX_SHADER]
        self.fragment_shaders = [st.ANIMATED_FRAGMENT_SHADER]
        self.texture_name = 'wood.jpg'
        self.time = Timer(duration=2.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.vertexes, self.indices, self.normals, self.uv = self.load_data()
        self.load_object()
        self.load_shader()
        self.load_texture()

        self.location = np.array([0.0, 0.0, 0.0])

        self.EYE = np.array([0.0, 0.0, 10.0])
        self.PREF = np.array([0.0, 0.0, -1.0])
        self.vv = np.array([0.0, 1.0, 0.0])
        self.N = (self.PREF - self.EYE) / np.linalg.norm(self.PREF - self.EYE)
        self.U = np.cross(self.N, self.vv) / np.linalg.norm(np.cross(self.N, self.vv))
        self.EYE_UP = np.cross(self.U, self.N)
        self.d = 0.1
        height = 500
        width = 500
        self.half_h = height / 2
        self.f = 100.0
        self.width = width
        self.height = height
        slope = np.sqrt((pow(self.d, 2) + pow((width / 2), 2)))
        self.fov = 2 * np.arctan(self.half_h / slope)
        left_bottom_near = self.EYE + self.d * self.N - self.half_h * self.U - self.half_h * self.EYE_UP
        right_top_near = self.EYE + self.d * self.N + self.half_h * self.U + self.half_h * self.EYE_UP
        self.VIEW = np.array([left_bottom_near[0], right_top_near[0], left_bottom_near[1], right_top_near[1],
                              np.array([self.d]), np.array([self.f])])
        self.LOOK_AT = np.array([0, 0, 0])
        self.ProjectionMatrix = glm.perspective(self.fov,
                                                float(self.width) / float(self.height), self.d, self.f)
        self.ViewMatrix = glm.lookAt(glm.vec3(self.EYE[0], self.EYE[1], self.EYE[2]),
                                     glm.vec3(self.LOOK_AT[0], self.LOOK_AT[1], self.LOOK_AT[2]),
                                     glm.vec3(self.vv[0], self.vv[1], self.vv[2])
                                     )
        self.MVP = self.ProjectionMatrix * self.ViewMatrix * glm.mat4(1.0)
class TestContext( wxinteractivecontext.wxInteractiveContext ):
    rotating = 1
    def OnInit( self ):
        self.sg = basenodes.sceneGraph(
            children = [
                basenodes.Transform(
                    children = [
                        basenodes.Shape(
                            geometry = basenodes.Box(
                                size = (2,3,4),
                            ),
                            appearance=basenodes.Appearance(
                                material = basenodes.Material(
                                    diffuseColor = (1,0,0),
                                ),
                            ),
                        ),
                    ],
                ),
                basenodes.PointLight(
                    location=(5,6,5),
                ),
            ],
        )
        self.time = Timer( duration = 32.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        self.rotation =  0
    def OnTimerFraction( self, event ):
        """Update our rotation from the timer event"""
        self.sg.children[0].rotation = (
            0,1,0,event.fraction()* 3.14149*2
        )
        
    def OnButtonPause( self, event ):
        """Handle the wxPython event from our button"""
        if self.rotating:
            self.time.pause()
        else:
            self.time.resume()
        self.rotating = not self.rotating
Exemple #25
0
    def OnInit( self ):
        """Load the image on initial load of the application"""
        print """This demo loads a VRML97 scenegraph and modifies
the rotation of the transform which contains one of the two boxes.
The ROUTE in the scene transmits this rotational change to the
transform which contains the other box."""
        self.sg = Loader.load( os.path.join("wrls","box.wrl") )
        self.trans = self.sg.getDEF( "Box01" )
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
Exemple #26
0
class TestContext(BaseContext):
    """Context to load wrls/box.wrl and watch routing changes

    The context loads the given file, gets a pointer to a
    particular node within the file, then modifies that node's
    rotation field. The routes in the file forward the changes
    to another node, causing both boxes on-screen to rotate.
    """
    initialPosition = (0, 0, 10)
    rot = 6.283

    def OnInit(self):
        """Load the image on initial load of the application"""
        print """This demo loads a VRML97 scenegraph and modifies
the rotation of the transform which contains one of the two boxes.
The ROUTE in the scene transmits this rotational change to the
transform which contains the other box."""
        self.sg = Loader.load(os.path.join("wrls", "box.wrl"))
        self.trans = self.sg.getDEF("Box01")
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()

    def OnTimerFraction(self, event):
        """Modify the node"""
        x, y, z, r = self.trans.rotation
        self.trans.rotation = x, y, z, (self.rot * event.fraction())
Exemple #27
0
class TestContext(BaseContext):
    def OnInit(self):
        """Load the image on initial load of the application"""
        print("""Should see a rotating star-field""")
        starfield = random.rand(9110, 3)
        self.coordinate = Coordinate(point=starfield, )
        self.color = Color(color=starfield, )
        self.transform = Transform(
            scale=(200, 200, 200),
            children=[
                Transform(
                    translation=(-.5, -.5, -.5),
                    children=[
                        Shape(geometry=PointSet(
                            coord=self.coordinate,
                            color=self.color,
                        ), ),
                    ],
                ),
            ],
        )
        self.sg = sceneGraph(children=[
            self.transform,
        ], )
        self.time = Timer(duration=90.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()

    def OnTimerFraction(self, event):
        """On event from the timer, generate new geometry"""
        self.transform.rotation = (0, 1, 0, 2 * math.pi * event.fraction())
Exemple #28
0
class TestContext( BaseContext ):
    def OnInit( self ):
        self.sg = scene
        self.addEventHandler( "keypress", name="a", function = self.OnAdd)
        self.time = Timer( duration = .1, repeating = 1 )
        self.time.addEventHandler( "cycle", self.OnAdd )
        self.time.register (self)
        self.time.start ()
        
    def OnAdd( self, event ):
        """Add a new box to the scene"""
        children = self.sg.children[0].children
        if len(children) > 128:
            children[:] = []
        else:
            cube = 10
            position = ( 
                (random.random()-.5)*cube,
                (random.random()-.5)*cube,
                (random.random()-.5)*cube 
            )
            color = (random.random(),random.random(),random.random())
            children.append( Transform(
                translation = position,
                children = [
                    Shape(
                        geometry = Teapot( size=.2),
                        appearance = Appearance(
                            material=Material( 
                                diffuseColor = color,
                            )
                        ),
                    ),
                ],
            ))
Exemple #29
0
class TestContext( BaseContext ):
    """Context to load wrls/box.wrl and watch routing changes

    The context loads the given file, gets a pointer to a
    particular node within the file, then modifies that node's
    rotation field. The routes in the file forward the changes
    to another node, causing both boxes on-screen to rotate.
    """
    initialPosition = (0,0,10)
    rot = 6.283
    def OnInit( self ):
        """Load the image on initial load of the application"""
        print """This demo loads a VRML97 scenegraph and modifies
the rotation of the transform which contains one of the two boxes.
The ROUTE in the scene transmits this rotational change to the
transform which contains the other box."""
        self.sg = Loader.load( os.path.join("wrls","box.wrl") )
        self.trans = self.sg.getDEF( "Box01" )
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
    def OnTimerFraction( self, event ):
        """Modify the node"""
        x,y,z,r = self.trans.rotation
        self.trans.rotation = x,y,z,(self.rot*event.fraction())
Exemple #30
0
 def OnInit( self ):
     """Scene set up and initial processing"""
     self.program = shaders.compileProgram(
         shaders.compileShader(
             '''
             varying vec3 normal;
             void main() {
                 normal = gl_NormalMatrix * gl_Normal;
                 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
             }
             ''',
             GL_VERTEX_SHADER,
         ),
         shaders.compileShader(
             '''
             uniform vec3 light_location;
             varying vec3 normal;
             void main() {
                 float intensity;
                 vec4 color;
                 vec3 n = normalize(normal);
                 vec3 l = normalize(light_location).xyz;
             
                 // quantize to 5 steps (0, .25, .5, .75 and 1)
                 intensity = (floor(dot(l, n) * 4.0) + 1.0)/4.0;
                 color = vec4(intensity*1.0, intensity*0.5, intensity*0.5,
                     intensity*1.0);
             
                 gl_FragColor = color;
             }
             ''',
             GL_FRAGMENT_SHADER,
         ),
     )
     self.light_uniform_loc = glGetUniformLocation( self.program, 'light_location' )
     self.time = Timer( duration = 2.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
Exemple #31
0
    def OnInit( self ):
        """Do all of our setup functions..."""
        if not glMultiTexCoord2f:
            print 'Multitexture not supported!'
            sys.exit(1)

        self.addEventHandler( "keypress", name="r", function = self.OnReverse)
        self.addEventHandler( "keypress", name="s", function = self.OnSlower)
        self.addEventHandler( "keypress", name="f", function = self.OnFaster)
        print 'r -- reverse time\ns -- slow time\nf -- speed time'
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        '''Load both of our textures.'''
        self.Load()
Exemple #32
0
class TestContext(BaseContext):
    rot = 6.283
    initialPosition = (0, 0, 3)

    def OnInit(self):
        self.sg = scene
        self.trans = self.sg.children[0]
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()

    def OnTimerFraction(self, event):
        """Modify the node"""
        self.trans.rotation = 0, 0, 1, (self.rot * event.fraction())
Exemple #33
0
class TestContext( BaseContext ):
    initialPosition = (0,0,3) # set initial camera position, tutorial does the re-positioning
    def OnInit( self ):
        """Load the image on initial load of the application"""
        print("""Should see a sine wave fading from green to red""")
        line = arange(0.0,1.0,.01)
        line2 = line[::-1]
        self.coordinate = Coordinate(
            point = map(None, line,[0]*len(line), [0]*len(line) ),
        )
        self.color = Color(
            color = map(None,line, [0]*len(line), line2 ),
        )
        self.sg = sceneGraph(
            children = [
                Transform(
                    translation = (-.5,0,0),
                    children = [
                        Shape(
                            geometry = PointSet(
                                coord = self.coordinate,
                                color = self.color,
                            ),
                        ),
                    ],
                ),
            ],
        )
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
    def OnTimerFraction( self, event ):
        """On event from the timer, generate new geometry"""
        xes = arange( 0.0, 1.0, 0.005 )
        range = (xes - event.fraction())*math.pi*2
        yes = sin( range )
        points = map(None,xes,yes,[0.0]*len(xes))
        colors = map(None,xes,xes[::-1],[0.0]*len(xes))
        self.coordinate.point = points
        self.color.color = colors
class TestContext( BaseContext ):
    initialPosition = (0,0,3) # set initial camera position, tutorial does the re-positioning
    def OnInit( self ):
        """Load the image on initial load of the application"""
        print """Should see a sine wave fading from green to red"""
        line = arange(0.0,1.0,.01)
        line2 = line[::-1]
        self.coordinate = Coordinate(
            point = map(None, line,[0]*len(line), [0]*len(line) ),
        )
        self.color = Color(
            color = map(None,line, [0]*len(line), line2 ),
        )
        self.sg = sceneGraph(
            children = [
                Transform(
                    translation = (-.5,0,0),
                    children = [
                        Shape(
                            geometry = PointSet(
                                coord = self.coordinate,
                                color = self.color,
                            ),
                        ),
                    ],
                ),
            ],
        )
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
    def OnTimerFraction( self, event ):
        """On event from the timer, generate new geometry"""
        xes = arange( 0.0, 1.0, 0.005 )
        range = (xes - event.fraction())*math.pi*2
        yes = sin( range )
        points = map(None,xes,yes,[0.0]*len(xes))
        colors = map(None,xes,xes[::-1],[0.0]*len(xes))
        self.coordinate.point = points
        self.color.color = colors
class TestContext(BaseContext):
    """Multi-texturing demo
    """
    initialPosition = (0, 0, 0)
    rotation = 0
    theta = 360 - 45
    phi = 30

    def OnInit(self):
        """Do all of our setup functions..."""
        if not glMultiTexCoord2f:
            print('Multitexture not supported!')
            sys.exit(1)

        self.update_sim = False
        vBuffer, uvBuffer, nBuffer, tBuffer, bBuffer, cBuffer, iBuffer, triangles = \
            loadMesh("TestMesh.obj", True, 0.001)

        self.indices = iBuffer
        self.vertices = vBuffer
        self.tex_coords = uvBuffer
        self.normals = nBuffer
        self.tangents = tBuffer
        self.biTangents = bBuffer
        self.colors = cBuffer

        normal_array = rasterizer.raster_vector_attrib(self.normals, self.tex_coords,\
                    triangles, SIM_SIZE, SIM_SIZE, UP)
        tangent_array = rasterizer.raster_vector_attrib(self.tangents, self.tex_coords,\
                    triangles, SIM_SIZE, SIM_SIZE, X_DIR)
        biTangent_array = rasterizer.raster_vector_attrib(self.biTangents, self.tex_coords,\
                    triangles, SIM_SIZE, SIM_SIZE, Y_DIR)

        self.fluid_sim = FluidSim.Fluid_Sim_2D(SIM_SIZE, SIM_SIZE, CELL_SIZE, DENSITY, GRAVITY,\
                    ATM_PRESSURE)
        for r in range(SIM_SIZE):
            for c in range(SIM_SIZE):
                self.fluid_sim.setNormal(r, c, normal_array[r][c])
                self.fluid_sim.setXTangent(r, c, tangent_array[r][c])
                self.fluid_sim.setYTangent(r, c, biTangent_array[r][c])

        sources = []
        for rc in INJECT_POINTS:
            for dr in range(-INJECT_RADIUS / 2, INJECT_RADIUS / 2 + 1):
                for dc in range(-INJECT_RADIUS / 2, INJECT_RADIUS / 2 + 1):
                    if dr * dr + dc * dc <= INJECT_RADIUS * INJECT_RADIUS:
                        sources.append((rc[0] + dr, rc[1] + dc))
        self.fluid_sim.markSources(sources)

        self.addEventHandler("keypress", name="r", function=self.OnReverse)
        self.addEventHandler("keypress", name="s", function=self.OnSlower)
        self.addEventHandler("keypress", name="f", function=self.OnFaster)
        self.addEventHandler("keypress", name="w", function=self.incPhi)
        self.addEventHandler("keypress", name="s", function=self.decPhi)
        self.addEventHandler("keypress", name="d", function=self.incTheta)
        self.addEventHandler("keypress", name="a", function=self.decTheta)
        self.addEventHandler("keypress", name="u", function=self.promptUpdate)
        print('r -- reverse time\ns -- slow time\nf -- speed time')
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        '''Load both of our textures.'''
        self.Load()

        self.frameCount = 0

    ### Timer callback
    def OnTimerFraction(self, event):
        self.rotation = event.fraction() * -360

    '''Keyboard callbacks, to allow for manipulating timer'''

    def OnReverse(self, event):
        self.time.internal.multiplier = -self.time.internal.multiplier
        print("reverse", self.time.internal.multiplier)

    def OnSlower(self, event):
        self.time.internal.multiplier = self.time.internal.multiplier / 2.0
        print("slower", self.time.internal.multiplier)

    def OnFaster(self, event):
        self.time.internal.multiplier = self.time.internal.multiplier * 2.0
        print("faster", self.time.internal.multiplier)

    def incTheta(self, event):
        self.theta += 0.5

    def decTheta(self, event):
        self.theta -= 0.5

    def incPhi(self, event):
        self.phi += 0.5

    def decPhi(self, event):
        self.phi -= 0.5

    def promptUpdate(self, event):
        self.update_sim = True

    def Load(self):
        self.image = self.loadImage("Checker_Sparse.png")
        self.watermap = self.loadWaterMap()

    def Render(self, mode):
        """Render scene geometry"""
        BaseContext.Render(self, mode)
        if mode.visible:
            glDisable(GL_CULL_FACE)
            glClearColor(0.5, 0.5, 0.5, 1.0)
            glClear(GL_COLOR_BUFFER_BIT)
            glEnable(GL_LIGHTING)

            glTranslatef(0.0, 8.0, -40.0)
            glRotated(self.phi + 180.0, 1, 0, 0)
            glRotated(self.theta, 0, 1, 0)
            '''We set up each texture in turn, the only difference 
            between them being their application model.  We want texture
            0 applied as a simple decal, while we want the light-map 
            to modulate the colour in the base texture.'''
            if USE_TEXTURE:
                glActiveTexture(GL_TEXTURE0)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_NEAREST)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_NEAREST)
                glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
                '''Enable the image (with the current texture unit)'''
                self.image()

            if SIMULATE:
                glActiveTexture(GL_TEXTURE1)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_NEAREST)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_NEAREST)
                glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
                '''Enable the image (with the current texture unit)'''

                if self.frameCount % 5 == 0:
                    self.update_sim = True
                if self.update_sim:
                    self.watermap = self.loadWaterMap()
                    for rc in INJECT_POINTS:
                        for dr in range(-INJECT_RADIUS / 2,
                                        INJECT_RADIUS / 2 + 1):
                            for dc in range(-INJECT_RADIUS / 2,
                                            INJECT_RADIUS / 2 + 1):
                                if dr * dr + dc * dc <= INJECT_RADIUS * INJECT_RADIUS:
                                    if (self.fluid_sim.getParticleCount() <
                                            MAX_PARTICLES):
                                        self.fluid_sim.inject(
                                            rc[0] + dr, rc[1] + dc,
                                            PARTICLE_INJECT_COUNT)
                                    if (XV_INJECT or YV_INJECT):
                                        print("NO!")
                                        self.fluid_sim.setXV(
                                            rc[0] + dr, rc[1] + dc, XV_INJECT)
                                        self.fluid_sim.setXV(
                                            rc[0] + dr, rc[1] + dc, XV_INJECT)
                                    if (P_INJECT):
                                        print("NAH!")
                                        self.fluid_sim.setP(
                                            rc[0] + dr, rc[1] + dc, P_INJECT)
                    self.fluid_sim.simFrame(TIME_STEP)
                    self.update_sim = False
                self.watermap()

            self.drawSurface()
            self.frameCount += 1

    def loadImage(self, imageName="nehe_wall.bmp"):
        """Load an image from a file using PIL."""
        try:
            from PIL.Image import open
        except ImportError:
            from Image import open
        glActiveTexture(GL_TEXTURE0_ARB)
        return texture.Texture(open(imageName))

    def loadWaterMap(self):
        origSources = self.fluid_sim.sources
        sources = set()
        for source in origSources:
            oldr = source[0]
            oldc = source[1]
            sources.add((oldr * SUBDIVIDE_FACTOR, oldc * SUBDIVIDE_FACTOR))

        fluid = []
        for sdr in range(SIM_SIZE * SUBDIVIDE_FACTOR):
            fluid.append([])
            for sdc in range(SIM_SIZE * SUBDIVIDE_FACTOR):
                fluid[sdr].append([])
        for r in range(SIM_SIZE):
            for c in range(SIM_SIZE):
                subdivCell = self.fluid_sim.subdivParticles(
                    r, c, SUBDIVIDE_FACTOR)
                for cr in range(SUBDIVIDE_FACTOR):
                    for cc in range(SUBDIVIDE_FACTOR):
                        for particle in subdivCell[cr][cc]:
                            fluid[r * SUBDIVIDE_FACTOR +
                                  cr][c * SUBDIVIDE_FACTOR +
                                      cc].append(particle)

        minV = rasterizer.np.array([255, 255, 255, 255])
        maxV = rasterizer.np.array([0, 0, 255, 255])
        sourceAlt = rasterizer.np.array([127, 127, 0, 0])
        data = rasterizer.fluid_to_texture(fluid, SIM_SIZE*SUBDIVIDE_FACTOR, SIM_SIZE*SUBDIVIDE_FACTOR, \
                float(RENDER_MAX), minV, maxV, sources, sourceAlt)
        glActiveTexture(GL_TEXTURE1_ARB)
        return texture.Texture(
            PIL.Image.frombuffer(
                "RGBA",
                (SIM_SIZE * SUBDIVIDE_FACTOR, SIM_SIZE * SUBDIVIDE_FACTOR),
                data))

    def drawSurface(self):
        """Draw a cube with texture coordinates"""
        glBegin(GL_TRIANGLES)
        for i in range(len(self.indices)):
            i0 = self.indices[i]
            mTexture(self.tex_coords[i0][0], self.tex_coords[i0][1])
            glVertex3f(self.vertices[i0][0], self.vertices[i0][1],
                       self.vertices[i0][2])
            glNormal3f(self.normals[i0][0], self.normals[i0][1],
                       self.normals[i0][2])
        glEnd()

    def OnIdle(self, ):
        """Request refresh of the context whenever idle"""
        self.triggerRedraw(1)
        return 1
Exemple #36
0
class TestContext( BaseContext ):
    """Demonstrates use of attribute types in GLSL
    """
    def OnInit( self ):
        """Initialize the context"""
        '''We've defined a uniform "tween" which represents the current 
        fractional mix between the two positions.
        
        When we were using the glVertexPointer/glColorPointer
        entry points, there were implicitly defined attribute values
        (gl_Vertex, gl_Color) that recieved our data-records.  With 
        legacy-free operation, we explicitly define the attribute values 
        which will be used.  They look very similar to the declarations
        for uniform values, save for the varying keyword.
        '''
        vertex = shaders.compileShader("""
            uniform float tween;
            attribute vec3 position;
            attribute vec3 tweened;
            attribute vec3 color;
            varying vec4 baseColor;
            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * mix(
                    vec4( position,1.0),
                    vec4( tweened,1.0),
                    tween
                );
                baseColor = vec4(color,1.0);
            }""",GL_VERTEX_SHADER)
        fragment = shaders.compileShader("""
            varying vec4 baseColor;
            void main() {
                gl_FragColor = baseColor;
            }""",GL_FRAGMENT_SHADER)
        self.shader = shaders.compileProgram(vertex,fragment)
        '''Since our VBO now has two position records and one colour 
        record, we have an extra 3 floats for each vertex record.'''
        self.vbo = vbo.VBO(
            array( [
                [  0, 1, 0, 1,3,0,  0,1,0 ],
                [ -1,-1, 0, -1,-1,0,  1,1,0 ],
                [  1,-1, 0, 1,-1,0, 0,1,1 ],
                
                [  2,-1, 0, 2,-1,0, 1,0,0 ],
                [  4,-1, 0, 4,-1,0, 0,1,0 ],
                [  4, 1, 0, 4,9,0, 0,0,1 ],
                [  2,-1, 0, 2,-1,0, 1,0,0 ],
                [  4, 1, 0, 1,3,0, 0,0,1 ],
                [  2, 1, 0, 1,-1,0, 0,1,1 ],
            ],'f')
        )
        '''As with uniforms, we must use opaque "location" values 
        to refer to our attributes when calling into the GL.'''
        self.position_location = glGetAttribLocation( 
            self.shader, 'position' 
        )
        self.tweened_location = glGetAttribLocation(
            self.shader, 'tweened',
        )
        self.color_location = glGetAttribLocation( 
            self.shader, 'color' 
        )
        self.tween_location = glGetUniformLocation(
            self.shader, 'tween',
        )
        '''The OpenGLContext timer class is setup here to provide 
        a 0.0 -> 1.0 animation event and pass it to the given function.'''
        self.time = Timer( duration = 2.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
    
    def Render( self, mode = 0):
        """Render the geometry for the scene."""
        BaseContext.Render( self, mode )
        glUseProgram(self.shader)
        '''We pass in the current (for this frame) value of our 
        animation fraction.  The timer will generate events to update
        this value during idle time.'''
        glUniform1f( self.tween_location, self.tween_fraction )
        try:
            '''Each attribute array, just as with the legacy pointer
            functions, will bind to the current (Vertex) VBO.  
            Because we are only using one VBO, we can bind once.  
            If our position arrays were stored in different VBOs, 
            we would need to bind and unbind the VBO for the
            corresponding glVertexAttribPointer calls.
            '''
            self.vbo.bind()
            try:
                '''As with the legacy pointers, we have to explicitly 
                enable the retrieval of values, without this, the GL 
                would attempt to read a value for every attribute that 
                is defined.  Non-enabled attributes get default values 
                for each vertex.  It is also possible to specify a single 
                value for an attribute to be used for each vertex 
                (as though the attribute were a uniform).
                '''
                glEnableVertexAttribArray( self.position_location )
                glEnableVertexAttribArray( self.tweened_location )
                glEnableVertexAttribArray( self.color_location )
                '''Our vertex array is now 36 bytes/record.  The 
                glVertexAttribPointer calls are very similar to the legacy 
                calls, save that they provide the attribute location 
                into which the data-array will feed.
                '''
                stride = 9*4
                glVertexAttribPointer( 
                    self.position_location, 
                    3, GL_FLOAT,False, stride, self.vbo 
                )
                glVertexAttribPointer( 
                    self.tweened_location, 
                    3, GL_FLOAT,False, stride, self.vbo+12
                )
                glVertexAttribPointer( 
                    self.color_location, 
                    3, GL_FLOAT,False, stride, self.vbo+24
                )
                glDrawArrays(GL_TRIANGLES, 0, 9)
            finally:
                self.vbo.unbind()
                '''As with the legacy pointer operations, we want to 
                clean up our array enabling so that any later calls 
                will not cause seg-faults when they try to read records
                from these arrays (potentially beyond the end of the
                arrays).'''
                glDisableVertexAttribArray( self.position_location )
                glDisableVertexAttribArray( self.tweened_location )
                glDisableVertexAttribArray( self.color_location )
        finally:
            glUseProgram( 0 )
    '''Our trivial event-handler function simply stores the event's 
    fraction as our tween_fraction value.'''
    tween_fraction = 0.0
    def OnTimerFraction( self, event ):
        frac = event.fraction()
        if frac > .5:
            frac = 1.0-frac 
        frac *= 2
        self.tween_fraction =frac
        self.triggerRedraw()
Exemple #37
0
class TestContext(BaseContext):
    def loadImage(self, imageName='gldrawpixels.png'):
        """Load an image from a file using PIL.
        This is closer to what you really want to do than the
        original port's crammed-together stuff that set global
        state in the loading method.  Note the process of binding
        the texture to an ID then loading the texture into memory.
        This didn't seem clear to me somehow in the tutorial.
        """
        try:
            from PIL.Image import open
        except ImportError:
            from Image import open
        im = open(imageName)
        try:
            ix, iy, image = im.size[0], im.size[1], im.tobytes(
                "raw", "RGBA", 0, -1)
        except SystemError:
            ix, iy, image = im.size[0], im.size[1], im.tobytes(
                "raw", "RGBX", 0, -1)
        return ix, iy, image

    def OnInit(self, ):
        """Initialisation"""
        print("""You should see two bitmap images traversing the screen
    diagonally.  If the GL.ARB.window_pos extension is not available
    then you will exit immediately.
    """)
        self.width, self.height, self.data = self.loadImage()
        global window_pos
        window_pos = self.extensions.initExtension("GL.ARB.window_pos")
        if not window_pos:
            print('GL_ARB_window_pos not supported!')
            sys.exit(testingcontext.REQUIRED_EXTENSION_MISSING)
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.x = 0
        self.y = 0

        try:
            window_pos.glWindowPos2dvARB(())
        except (error.CopyError, GLerror, ValueError) as err:
            print('Correct handling of incorrect parameters', err)
        except Exception as err:
            traceback.print_exc()
            print('Incorrect handling of incorrect parameters')
        try:
            window_pos.glWindowPos3dvARB(())
        except (error.CopyError, GLerror, ValueError) as err:
            print('Correct handling of incorrect parameters', err)
        except Exception as err:
            traceback.print_exc()
            print('Incorrect handling of incorrect parameters')

    def OnTimerFraction(self, event):
        """Set new position..."""
        width, height = self.getViewPort()
        self.x = width * event.fraction()
        self.y = height * event.fraction()

    def Render(self, mode=None):
        BaseContext.Render(self, mode)
        # we aren't affected by the matrices (which is the point)
        glTranslate(100, 0, 0)
        if mode.visible and not mode.transparent:
            format = GL_RGBA
            type = GL_UNSIGNED_BYTE
            glEnable(GL_ALPHA_TEST)
            glAlphaFunc(GL_GREATER, 0)
            glPixelStorei(GL_PACK_ALIGNMENT, 1)
            glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

            width, height = self.getViewPort()
            window_pos.glWindowPos2dARB(self.x, self.y)

            glDrawPixels(
                self.width,
                self.height,
                format,
                type,
                self.data,
            )
            window_pos.glWindowPos2fvARB(
                GLfloat_2(self.x,
                          self.getViewPort()[1] - self.y))
            glDrawPixels(
                self.width,
                self.height,
                format,
                type,
                self.data,
            )
Exemple #38
0
    def OnInit(self):
        """Scene set up and initial processing"""
        print """You should see a cone over a black background
    The cone should have a mapped texture (a stained-glass window)
    and should be centered on the window.
"""
        print 'press i to choose another texture for the box'
        self.addEventHandler('keypress', name='i', function=self.OnImageSwitch)
        print 'press s to choose another size for the box'
        self.addEventHandler('keypress', name='s', function=self.OnSizeSwitch)
        self.appearance = Appearance(
            material=Material(
                diffuseColor=(1, 0, 0),
                specularColor=(.5, .5, .5),
            ),
            texture=ImageTexture(url=[images[0]]),
        )
        self.cone = Shape(
            geometry=Cone(),
            appearance=self.appearance,
        )
        self.cylinder = Shape(
            geometry=Cylinder(),
            appearance=self.appearance,
        )
        self.box = Shape(
            geometry=Box(),
            appearance=self.appearance,
        )
        self.gear = Shape(
            geometry=Gear(),
            appearance=self.appearance,
        )
        self.teapot = Shape(
            geometry=Teapot(),
            appearance=self.appearance,
        )
        self.sphere = Shape(
            geometry=Sphere(),
            appearance=self.appearance,
        )
        self.ifs = Shape(
            geometry=IndexedFaceSet(
                coord=Coordinate(point=[[-1, 0, 0], [1, 0, 0], [1, 1, 0],
                                        [-1, 1, 0]], ),
                coordIndex=[0, 1, 2, -1, 0, 2, 3],
                color=Color(color=[[0, 0, 1], [1, 0, 0]], ),
                colorIndex=[0, 1, 0, -1, 0, 0, 1],
                solid=False,
                normalPerVertex=True,
            ),
            appearance=self.appearance,
        )
        self.sg = Transform(
            children=[
                Transform(
                    translation=(4, 0, 0),
                    children=[self.cone],
                ),
                Transform(
                    translation=(0, 0, 0),
                    children=[self.box],
                ),
                Transform(
                    translation=(-4, 0, 0),
                    children=[self.cylinder],
                ),
                Transform(
                    translation=(0, 4, 0),
                    children=[self.gear],
                    scale=(3, 3, 3),
                ),
                Transform(
                    translation=(0, -4, 0),
                    children=[self.teapot],
                    scale=(.5, .5, .5),
                ),
                Transform(
                    translation=(4, -4, 0),
                    children=[self.sphere],
                ),
                Transform(
                    translation=(-4, -4, 0),
                    children=[self.ifs],
                ),
                SimpleBackground(color=(.5, .5, .5), ),
            ],
            scale=(.75, .75, .75),
        )
        self.time = Timer(duration=15.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
Exemple #39
0
class TestContext(BaseContext):
    currentImage = 0
    currentSize = 0

    def OnInit(self):
        """Scene set up and initial processing"""
        print """You should see a cone over a black background
    The cone should have a mapped texture (a stained-glass window)
    and should be centered on the window.
"""
        print 'press i to choose another texture for the box'
        self.addEventHandler('keypress', name='i', function=self.OnImageSwitch)
        print 'press s to choose another size for the box'
        self.addEventHandler('keypress', name='s', function=self.OnSizeSwitch)
        self.appearance = Appearance(
            material=Material(
                diffuseColor=(1, 0, 0),
                specularColor=(.5, .5, .5),
            ),
            texture=ImageTexture(url=[images[0]]),
        )
        self.cone = Shape(
            geometry=Cone(),
            appearance=self.appearance,
        )
        self.cylinder = Shape(
            geometry=Cylinder(),
            appearance=self.appearance,
        )
        self.box = Shape(
            geometry=Box(),
            appearance=self.appearance,
        )
        self.gear = Shape(
            geometry=Gear(),
            appearance=self.appearance,
        )
        self.teapot = Shape(
            geometry=Teapot(),
            appearance=self.appearance,
        )
        self.sphere = Shape(
            geometry=Sphere(),
            appearance=self.appearance,
        )
        self.ifs = Shape(
            geometry=IndexedFaceSet(
                coord=Coordinate(point=[[-1, 0, 0], [1, 0, 0], [1, 1, 0],
                                        [-1, 1, 0]], ),
                coordIndex=[0, 1, 2, -1, 0, 2, 3],
                color=Color(color=[[0, 0, 1], [1, 0, 0]], ),
                colorIndex=[0, 1, 0, -1, 0, 0, 1],
                solid=False,
                normalPerVertex=True,
            ),
            appearance=self.appearance,
        )
        self.sg = Transform(
            children=[
                Transform(
                    translation=(4, 0, 0),
                    children=[self.cone],
                ),
                Transform(
                    translation=(0, 0, 0),
                    children=[self.box],
                ),
                Transform(
                    translation=(-4, 0, 0),
                    children=[self.cylinder],
                ),
                Transform(
                    translation=(0, 4, 0),
                    children=[self.gear],
                    scale=(3, 3, 3),
                ),
                Transform(
                    translation=(0, -4, 0),
                    children=[self.teapot],
                    scale=(.5, .5, .5),
                ),
                Transform(
                    translation=(4, -4, 0),
                    children=[self.sphere],
                ),
                Transform(
                    translation=(-4, -4, 0),
                    children=[self.ifs],
                ),
                SimpleBackground(color=(.5, .5, .5), ),
            ],
            scale=(.75, .75, .75),
        )
        self.time = Timer(duration=15.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()

    def OnTimerFraction(self, event):
        self.sg.rotation = array([0, 1, 0, event.fraction() * pi * 2], 'f')
        self.appearance.material.diffuseColor = [event.fraction()] * 3
        self.triggerRedraw(False)

    def OnImageSwitch(self, event=None):
        """Choose a new mapped texture"""
        self.currentImage = currentImage = self.currentImage + 1
        newImage = images[currentImage % len(images)]
        self.appearance.texture.url = [newImage]
        print "new image (loading) ->", newImage

    def OnSizeSwitch(self, event=None):
        """Choose a new size"""
        self.currentSize = currentSize = self.currentSize + 1
        newSize = cone_sizes[currentSize % len(cone_sizes)]
        self.cone.geometry.bottomRadius = newSize
        newSize = cone_sizes[(currentSize + 1) % len(cone_sizes)]
        self.cone.geometry.height = newSize

        self.box.geometry.size = (newSize, newSize, newSize)
        self.cylinder.geometry.height = newSize
        self.cylinder.geometry.radius = newSize * .25
        self.gear.geometry.outer_radius = newSize * .25
        self.teapot.geometry.size = newSize
        self.sphere.geometry.radius = newSize
        print "new size ->", newSize
        self.triggerRedraw(True)
Exemple #40
0
	def OnInit( self ):
		
		self.drawCapture = 0
		self.capturedImage = ()
		self.useStringDraw = 0
		self.reverseShape = 0
		self.capturedImageFormat = GL_RGB
		
		self.planRot = 0;
		self.frameIter = 0;
		
		self.iter = 0
		self.strPos = 0
		self.newSystemTime = 45
		self.systemIterator = 0
		self.uniqueIDs = []
		
		self.whichSTR = 0
		

		glutReshapeWindow( 1400, 850)
		glutPositionWindow( 0, 0 )
		glutFullScreen( )
		
		self.time = Timer( duration = 60.0, repeating = 1 )
		self.time.addEventHandler( "fraction", self.OnTimerFraction )
		self.time.register (self)
		self.time.start ()
		
		#self.updater = Timer(duration = 61, repeating = 1)
		#self.updater.addEventHandler("cycle", self.updateFromSQL )
		#self.updater.register(self)
		#self.updater.start ()
		
		
		self.rot = 0
		
		self.offset = 3
		
		#dragging flag
		self.startDrag = 0
		
		#holder for last detail rendered planet
		self.lastDetail = ()
		
		
		#make some random planets and systems
		#self.universe = universe.Universe()
		
		self.addEventHandler( 'keypress', name='s', function=self.OnSave )
		
		#get fonts
		providers = fontprovider.getProviders( 'solid' )
		if not providers:
			raise ImportError( """NONONO solid font providers registered! Demo won't function properly!""" )
		registry = self.getTTFFiles()
		styles = []
		for font in registry.familyMembers( 'SANS' ):
			names = registry.fontMembers( font, 400, 0)
			for name in names:
				styles.append( fontstyle3d.FontStyle3D(
					family = [name],
					size = .06,
					justify = "LEFT",
					thickness = .02,
					quality = 3,
					renderSides = 1,
					renderFront = 1,
					renderBack = 1,
				))
		self.styles = styles
		
		#render all ascii
		self.ascii = []
		asciiNum = 32
		while asciiNum<128:
			self.ascii.append( basenodes.Text( fontStyle=self.styles[0], string=chr(asciiNum) ) )
			asciiNum += 1
						
				
		####	Starting SQL Integration Here
		self.universe = universe.Universe()
		numSys = 1
		self.universe.addSys(self.systemIterator)
		
		conn = MySQLdb.connect( host = "ec2-75-101-245-127.compute-1.amazonaws.com",
								user = "******",
								passwd = "ohhai",
								db = "wikihole")
		self.stringArray = []
		cursor = conn.cursor()
		cursor.execute( "SELECT * FROM history")
		self.planetMoons = list();
		offsetset = 0
		while (1):
			row = cursor.fetchone()
			if row == None:
				break
			print "%s\t%s\t%s" % (row[0], row[2], row[1])	
			if(not offsetset):
				self.offset = row[0]
				offsetset = 1
				lastTime = "%s" % row[2]
				thisTime = "%s" % row[2]
			else:
				lastTime = thisTime
				thisTime = "%s" % row[2]
			
			if( not gethistory.timeDiff(lastTime, thisTime, self.newSystemTime) ):
				self.systemIterator = self.systemIterator + 1
				self.universe.addSys(self.systemIterator)
				print "MADE NEW SYSTEM"
				#print lastTime
				#print thisTime
			
			url = row[1]
			
			self.uniqueIDs.append(row[0])
			
			imageurls = gethistory.getImageUrls(url)
			
			
			#make geometry array for description
			geom = []
			gNum = 0
			descripStr = gethistory.getDescription(url)
			
			while gNum<200:
				strr = descripStr[ gNum ]  #self.bigString[ gNum ] 
				asciiNumber = ord( strr )-32
				if( not asciiNumber>=0 or not asciiNumber<=95 ):
					asciiNumber = 0
					print "OUTOFBOUNDS"
				geom.append( self.ascii[ asciiNumber ] )
				gNum += 1
				
			if( self.whichSTR == 0):
				self.whichSTR = 1
			else:
				self.whichSTR = 0
				
			print self.whichSTR
							
				
			#render font geom for title
			names = url.split('/')
			wikititle = names[len(names) - 1]
			wikititle = wikititle.replace('_', ' ')
			self.stringArray.append(wikititle)
			title = basenodes.Text( fontStyle=self.styles[0], string=wikititle )
			
			#get list of image urls for planet moons
			fileList = list()
			for image in imageurls:
				linetoExec = "wget " + image

				fullpath = image.split('/')
				existsOrNot =  os.path.exists( fullpath[len(fullpath) - 1] )
				if(existsOrNot):
					fileList.append( fullpath[len(fullpath) - 1] )
				else:
					fileList.append( fullpath[len(fullpath) - 1] )
					os.system(linetoExec)  #uncomment this before real runs
			#self.planetMoons.append(fileList)
			
			####
			#FINALLY add the planet to the current solar system
			self.universe.addPlanet(row[0], len(imageurls), title, geom, fileList)
					

						
		"""Setup callbacks and build geometry for rendering"""
		#on mouse down
		self.addEventHandler( "mousebutton", button = 0, state=1, function = self.mouseDown )
		#on mouse up
		self.addEventHandler( "mousebutton", button = 0, state = 0, function = self.mouseUp )
				
		glutinteractivecontext.GLUTInteractiveContext.setupDefaultEventCallbacks(self)
		
		self.initialPosition = ( 0,0,20 )
		self.STEPDISTANCE = 5.0
		self.newPos = self.initialPosition
		self.goTo = 0
class TestContext( BaseContext ):
    """Demonstrates use of attribute types in GLSL
    """
    def OnInit( self ):
        """Initialize the context"""
        '''== Phong and Blinn Reflectance ==

        A shiny surface will tend to have a "bright spot" at the point 
        on the surface where the angle of incidence for the reflected
        light ray and the viewer's ray are (close to) equal.  
        A perfect mirror would have the brights spot solely when the 
        two vectors are exactly equal, while a perfect Lambertian
        surface would have the "bright spot" spread across the entire
        surface.
        
        The Phong rendering process models this as a setting, traditionally
        called material "shininess" in Legacy OpenGL.  This setting acts 
        as a power which raises the cosine (dot product) of the 
        angle between the reflected ray and the eye.  The calculation of 
        the cosine (dot product) of the two angles requires that we do 
        a dot product of the two angles once for each vertex/fragment 
        for which we wish to calculate the specular reflectance, we also 
        have to find the angle of reflectance before we can do the 
        calculation:'''
        """
            L_dir = (V_pos-L_pos)
            R = 2N*(dot( N, L_dir))-L_dir
            // Note: in eye-coordinate system, Eye_pos == (0,0,0)
            Spec_factor = pow( dot( R, V_pos-Eye_pos ), shininess)
        """
        '''which, as we can see, involves the vertex position in a number 
        of stages of the operation, so requires recalculation all through 
        the rendering operation.
        
        There is, however, a simplified version of Phong Lighting called 
        [http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model Blinn-Phong]
        which notes that if we were to do all of our calculations in 
        "eye space", and were to assume that (as is normal), the eye 
        and light coordinates will not change for a rendering pass,
        (note: this limits us to directional lights!) we 
        can use a pre-calculated value which is the bisecting angle
        between the light-vector and the view-vector, called the 
        "half vector" to 
        perform approximately the same calculation.  With this value:'''
        """
            // note that in Eye coordinates, Eye_EC_dir == 0,0,-1
            H = normalize( Eye_EC_dir + Light_EC_dir )
            Spec_factor = pow( dot( H, N ), shininess )
        """
        '''Note: however, that the resulting Spec_factor is not *precisely*
        the same value as the original calculation, so the "shininess"
        exponent must be slightly lower to approximate the value that
        Phong rendering would achieve.  The value is, however, considered
        close to "real world" materials, so the Blinn method is generally 
        preferred to Phong.
        
        Traditionally, n_dot_pos would be cut off at 0.0, but that would 
        create extremely hard-edged cut-offs for specular color.  Here 
        we "fudge" the result by 0.05
        '''
        phong_weightCalc = """
        vec2 phong_weightCalc( 
            in vec3 light_pos, // light position
            in vec3 half_light, // half-way vector between light and view
            in vec3 frag_normal, // geometry normal
            in float shininess
        ) {
            // returns vec2( ambientMult, diffuseMult )
            float n_dot_pos = max( 0.0, dot( 
                frag_normal, light_pos
            ));
            float n_dot_half = 0.0;
            if (n_dot_pos > -.05) {
                n_dot_half = pow(max(0.0,dot( 
                    half_light, frag_normal
                )), shininess);
            }
            return vec2( n_dot_pos, n_dot_half);
        }		
        """
        '''We are going to use per-fragment rendering.
        As a result, our vertex shader becomes very simple, just arranging
        for the Normals to be varied across the surface.
        '''
        vertex = shaders.compileShader( 
        """
        attribute vec3 Vertex_position;
        attribute vec3 Vertex_normal;
        
        varying vec3 baseNormal;
        void main() {
            gl_Position = gl_ModelViewProjectionMatrix * vec4( 
                Vertex_position, 1.0
            );
            baseNormal = gl_NormalMatrix * normalize(Vertex_normal);
        }""", GL_VERTEX_SHADER)
        '''Our fragment shader looks much like our previous tutorial's 
        vertex shader.  As before, we have lots of uniform values,
        but now we also calculate the light's half-vector (in eye-space 
        coordinates).  The phong_weightCalc function does the core Blinn 
        calculation, and we simply use the resulting factor to add to 
        the colour value for the fragment.
        
        Note the use of the eye-coordinate-space to simplify the 
        half-vector calculation, the eye-space eye-vector is always 
        the same value (pointing down the negative Z axis), 
        and the eye-space eye-coordinate is always (0,0,0), so the 
        eye-to-vertex vector is always the eye-space vector position.
        '''
        fragment = shaders.compileShader( phong_weightCalc + """
        uniform vec4 Global_ambient;
        
        uniform vec4 Light_ambient;
        uniform vec4 Light_diffuse;
        uniform vec4 Light_specular;
        uniform vec3 Light_location;
        
        uniform float Material_shininess;
        uniform vec4 Material_specular;
        uniform vec4 Material_ambient;
        uniform vec4 Material_diffuse;
        
        varying vec3 baseNormal;
        void main() {
            // normalized eye-coordinate Light location
            vec3 EC_Light_location = normalize(
                gl_NormalMatrix * Light_location
            );
            // half-vector calculation 
            vec3 Light_half = normalize(
                EC_Light_location - vec3( 0,0,-1 )
            );
            vec2 weights = phong_weightCalc(
                EC_Light_location,
                Light_half,
                baseNormal,
                Material_shininess
            );
            
            gl_FragColor = clamp( 
            (
                (Global_ambient * Material_ambient)
                + (Light_ambient * Material_ambient)
                + (Light_diffuse * Material_diffuse * weights.x)
                // material's shininess is the only change here...
                + (Light_specular * Material_specular * weights.y)
            ), 0.0, 1.0);
        }
        """, GL_FRAGMENT_SHADER)
        
        self.shader = shaders.compileProgram(vertex,fragment)
        '''Here's the call that creates the two VBOs and the 
        count of records to render from them. If you're curious 
        you can read through the source code of the 
        OpenGLContext.scenegraph.quadrics module to read the 
        mechanism that generates the values.
        
        The sphere is a simple rendering mechanism, as for a 
        unit-sphere at the origin, the sphere's normals are the 
        same as the sphere's vertex coordinate.  The complexity 
        comes primarily in generating the triangle indices that 
        link the points generated.
        '''
        #self.coords,self.indices,self.count = Sphere( 
        #    radius = 3 
        #).compile()

        self.coords,self.indices,self.count = Sphere(radius=3).compile()

        '''We have a few more uniforms to control the specular 
        components.  Real-world coding would also calculate the 
        light's half-vector and provide it as a uniform (so that 
        it would only need to be calculated once), but we are going 
        to do the half-vector calculation in the shader to make 
        it obvious what is going on.  The legacy OpenGL pipeline 
        provides the value pre-calculated as part of the light structure 
        in GLSL.
        '''
        for uniform in (
            'Global_ambient',
            'Light_ambient','Light_diffuse','Light_location',
            'Light_specular',
            'Material_ambient','Material_diffuse',
            'Material_shininess','Material_specular',
        ):
            location = glGetUniformLocation( self.shader, uniform )
            if location in (None,-1):
                print 'Warning, no uniform: %s'%( uniform )
            setattr( self, uniform+ '_loc', location )
        for attribute in (
            'Vertex_position','Vertex_normal',
        ):
            location = glGetAttribLocation( self.shader, attribute )
            if location in (None,-1):
                print 'Warning, no attribute: %s'%( uniform )
            setattr( self, attribute+ '_loc', location )

        #Add a timer
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        self.rotation =  0
        self.sensor = PhotoSensor()
        self.sensor.calibrate_ambient()


    def OnTimerFraction( self, event ):
        r = self.sensor.getSensorReading()
        angle = self.sensor.getAngle(r)
        self.rotation = angle/180.0 *  pi
        

    def getLightLocation(self):
        # read from serial port
        return [math.cos(self.rotation),
                math.sin(self.rotation),0]*5


    def Render( self, mode = None):
        """Render the geometry for the scene."""
        BaseContext.Render( self, mode )
        glUseProgram(self.shader)
        try:
            '''==Indexed VBO Rendering==
            
            You'll notice here that we are binding two different VBO 
            objects.  As we mentioned above, the Sphere renderer 
            generated both VBOs, but doesn't the second binding replace 
            the first binding?  That is, why doesn't OpenGL try to read 
            the Vertex data out of the indices VBO?
            
            OpenGL defines multiple binding "targets" for VBOs, the 
            first VBO (vertices) was bound to the GL_ARRAY_BUFFER
            target (the default for the class), which is used for reading 
            per-vertex data arrays, while the indices buffer was defined
            as targetting the GL_ELEMENT_ARRAY_BUFFER, which is used
            solely for reading indices.
            
            Each target can be bound to a different VBO, and thus we can
            bind both VBOs at the same time without confusion.
            '''
            self.coords.bind()
            self.indices.bind()
            '''Here, being lazy, we use the numpy array's nbytes value 
            to specify the stride between records.  The VBO object has 
            a "data" value which is the data-set which was initially 
            passed to the VBO constructor.  The first element in this 
            array is a single vertex record.  This array happens to have 
            8 floating-point values (24 bytes), the first three being 
            the vertex position, the next two being the texture coordinate 
            and the last three being the vertex normal.  We'll ignore 
            the texture coordinate for now.
            '''
            stride = self.coords.data[0].nbytes
            try:
                glUniform4f( self.Global_ambient_loc, .05,.05,.05,.1 )
                glUniform4f( self.Light_ambient_loc, .1,.1,.1, 1.0 )
                glUniform4f( self.Light_diffuse_loc, .25,.25,.25,1 )
                '''We set up a yellow-ish specular component in the 
                light and move it to rest "just over our right shoulder"
                in relation to the initial camera.'''
                glUniform4f( self.Light_specular_loc, 0.0,1.0,0,1 )

                lloc = self.getLightLocation()
                glUniform3f( self.Light_location_loc, lloc[0],
                             lloc[1], lloc[2])
                
                glUniform4f( self.Material_ambient_loc, .1,.1,.1, 1.0 )
                glUniform4f( self.Material_diffuse_loc, .15,.15,.15, 1 )
                '''We make the material have a bright specular white 
                colour and an extremely "shiny" surface.  The shininess 
                value has the effect of reducing the area of the
                highlight, as the cos of the angle is raised 
                to the power of the (fractional) shininess.'''
                glUniform4f( self.Material_specular_loc, 1.0,1.0,1.0, 1.0 )
                glUniform1f( self.Material_shininess_loc, .95)
                glEnableVertexAttribArray( self.Vertex_position_loc )
                glEnableVertexAttribArray( self.Vertex_normal_loc )
                glVertexAttribPointer( 
                    self.Vertex_position_loc, 
                    3, GL_FLOAT,False, stride, self.coords
                )
                glVertexAttribPointer( 
                    self.Vertex_normal_loc, 
                    3, GL_FLOAT,False, stride, self.coords+(5*4)
                )
                '''Here we introduce the OpenGL call which renders via 
                an index-array rather than just rendering vertices in 
                definition order.  The last two arguments tell OpenGL 
                what data-type we've used for the indices (the Sphere 
                renderer uses shorts).  The indices VBO is actually 
                just passing the value c_void_p( 0 ) (i.e. a null pointer),
                which causes OpenGL to use the currently bound VBO for 
                the GL_ELEMENT_ARRAY_BUFFER target.
                '''
                glDrawElements(
                    GL_TRIANGLES, self.count,
                    GL_UNSIGNED_SHORT, self.indices
                )
            finally:
                '''Note the need to unbind *both* VBOs, we have to free 
                *both* VBO targets to avoid any other rendering operation 
                from trying to access the VBOs.'''
                self.coords.unbind()
                self.indices.unbind()
                glDisableVertexAttribArray( self.Vertex_position_loc )
                glDisableVertexAttribArray( self.Vertex_normal_loc )
        finally:
            glUseProgram( 0 )
Exemple #42
0
class TestContext( BaseContext ):
    """Shadow rendering tutorial code"""
    '''We're going to get up nice and close to our geometry in the
    initial view'''
    initialPosition = (.5,1,3)
    '''If we set lightViewDebug we will keep the light's view in the context
    rather than clearing the background before drawing the scene.'''
    lightViewDebug = False
    '''=Scene Set Up=

    Our tutorial requires a number of OpenGL extensions.  We're going
    to test for these extensions using the glInit* functions.  These are
    PyOpenGL-2.x style queries which will return True if the extension is
    available.  PyOpenGL 3.x also allows you to do bool( entryPoint ) to
    check if an entry point is available, but that does not allow you to
    check for extensions which *only* define new constants.
    '''
    def OnInit( self ):
        """Initialize the context with GL active"""
        if not glInitShadowARB() or not glInitDepthTextureARB():
            print 'Missing required extensions!'
            sys.exit( testingcontext.REQUIRED_EXTENSION_MISSING )
        '''Configure some parameters to make for nice shadows
        at the expense of some extra calculations'''
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
        glEnable( GL_POLYGON_SMOOTH )
        '''We create the geometry for our scene in a method to allow
        later tutorials to subclass and provide more interesting scenes.
        '''
        self.geometry = self.createGeometry()
        '''We'll use OpenGLContext's rendering passes to render the geometry 
        each time we need to do so...'''
        self.geometryPasses = flat.FlatPass(self.geometry,self)
        '''To make the demo a little more interesting, we're going to
        animate the first light's position and direction.  Here we're setting
        up a raw Timer object.  OpenGLContext scenegraph timers can't be used
        as we're not using the scenegraph mechanisms.
        '''
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        '''Here are the lights we're going to use to cast shadows.'''
        self.lights = self.createLights()
        self.addEventHandler( "keypress", name="s", function = self.OnToggleTimer)
    def createLights( self ):
        """Create the light's we're going to use to cast shadows"""
        '''Our first tutorial can only handle "spotlights", so we'll limit
        ourselves to those.'''
        return [
            SpotLight(
                location = [0,5,10],
                color = [1,.95,.95],
                intensity = 1,
                ambientIntensity = 0.10,
                direction = [0,-5,-10],
            ),
            SpotLight(
                location = [3,3,3],
                color = [.75,.75,1.0],
                intensity = .5,
                ambientIntensity = .05,
                direction = [-3,-3,-3],
            ),
        ]
    def createGeometry( self ):
        """Create a simple VRML scenegraph to be rendered with shadows"""
        '''This simple scene is a Teapot and a tall thin box on a flat
        box.  It's not particularly exciting, but it does let us see the
        shadows quite clearly.'''
        return Transform(
            children = [
                Transform(
                    translation = (0,-.38,0),
                    children = [
                        Shape(
                            DEF = 'Floor',
                            geometry = Box( size=(5,.05,5)),
                            appearance = Appearance( material=Material(
                                diffuseColor = (.7,.7,.7),
                                shininess = .8,
                                ambientIntensity = .1,
                            )),
                        ),
                    ],
                ),
                Transform(
                    translation = (0,0,0),
                    children = [
                        Shape(
                            DEF = 'Tea',
                            geometry = Teapot( size = .5 ),
                            appearance = Appearance(
                                material = Material(
                                    diffuseColor =( .5,1.0,.5 ),
                                    ambientIntensity = .2,
                                    shininess = .5,
                                ),
                            ),
                        )
                    ],
                ),
                Transform(
                    translation = (2,3.62,0),
                    children = [
                        Shape(
                            DEF = 'Pole',
                            geometry = Box( size=(.1,8,.1) ),
                            appearance = Appearance(
                                material = Material(
                                    diffuseColor =( 1.0,0,0 ),
                                    ambientIntensity = .4,
                                    shininess = 0.0,
                                ),
                            ),
                        )
                    ],
                ),
            ],
        )
    def OnTimerFraction( self, event ):
        """Update light position/direction"""
        '''Every cycle we want to do a full rotation, and we want the
        light to be 10 units from the y axis in the x,z plane.
        All else is math.'''
        light = self.lights[0]
        a = event.fraction() * 2 * pi
        xz = array( [
            sin(a),cos(a),
        ],'f') * 10 # radius
        position = light.location
        position[0] = xz[0]
        position[2] = xz[1]
        light.location = position
        '''We point the light at the origin, mostly because it's easy.'''
        light.direction = -position
    def OnToggleTimer( self, event ):
        """Allow the user to pause/restart the timer."""
        if self.time.active:
            self.time.pause()
        else:
            self.time.resume()

    '''=Overall Rendering Process=

    OpenGLContext does a lot of "boilerplate" setup code to establish
    a perspective and model-view matrix, clear the background, and
    generally get you to a "normal 3D rendering" setup before it calls
    this method (Render).  It will *not* call this method if we have
    a scenegraph as self.sg, as then it will use to optimized "Flat"
    rendering engine.

    The overall process for the shadow rendering code looks like this:

        * for each light, render a depth-texture and calculate a texture
          matrix
        * restore the perspective and model-view matrices for the camera
        * render the scene with only ambient lighting
        * for each light, render the scene with diffuse and specular lighting
          with the depth-texture and texture matrix filtering the areas
          which are affected.

    We only want to apply this process for the "normal diffuse" rendering
    mode, not, for instance, for the mouse-selection passes or the
    transparent rendering pass (transparent shadows will have to wait for
    another tutorial).
    '''
    def Render( self, mode):
        assert mode
        BaseContext.Render( self, mode )
        self.geometryPasses.setViewPlatform( mode.viewPlatform )
        if mode.visible and mode.lighting and not mode.transparent:
            '''These settings tell us we are being asked to do a
            regular opaque rendering pass (with lighting).  This is
            where we are going to do our shadow-rendering multi-pass.'''
            shadowTokens = [
                (light,self.renderLightTexture( light, mode ))
                for light in self.lights[:self.lightViewDebug or len(self.lights)]
            ]
            '''Since our depth buffer currently has the light's view rendered
            into it, we need to clear it before we render our geometry from the
            camera's viewpoint.'''
            glClear(GL_DEPTH_BUFFER_BIT)
            '''OpenGLContext's camera is represented by a "View Platform"
            this camera's view has already been set up once during this
            rendering pass, but our light-texture-rendering pass will have
            reset the matrices to match the light's perspective.

            The view platform object has a method to render the matrices
            using regular OpenGL legacy calls (the "Flat" renderer calculates
            and loads these values directly).  We just call this method to
            have the platform restore its state.  The "identity" parameter
            tells the platform to do a glLoadIdentity() call for each matrix
            first.
            '''
            platform = self.getViewPlatform()
            platform.render( identity = True )
            '''We do our ambient rendering pass.'''
            self.renderAmbient( mode )
            '''Then we do the diffuse/specular lighting for our lights.
            We want to make our "extra light" blend into the current light
            reflected from the surfaces at 1:1 ratio, so we enable blending
            before doing the diffuse/specular pass.
            '''
            glEnable(GL_BLEND)
            glBlendFunc(GL_ONE,GL_ONE)
            try:
                for i,(light,(texture,textureMatrix)) in enumerate(shadowTokens):
                    self.renderDiffuse( light, texture, textureMatrix, mode, id=i )
            finally:
                glDisable(GL_BLEND)
        else:
            '''If we are *not* doing the shadowed opaque rendering pass,
            just visit the "scenegraph" with our mode.'''
            self.drawScene( mode, mode.getModelView() )
    '''Let's get the simple part out of the way first; drawing the geometry.
    OpenGLContext has two different rendering engines.  One is an
    optimized "Flat" renderer, and the other is a hierarchic "traversing"
    renderer which uses a visitor pattern to traverse the scenegraph for
    each pass.  For our purposes, this slower traversing renderer is
    sufficient, and is easily invoked.'''
    def drawScene( self, mode, matrix ):
        """Draw our scene at current animation point"""
        glMatrixMode( GL_MODELVIEW )
        glLoadMatrixf( matrix )
        glPushMatrix()
        try:
            self.geometryPasses.renderGeometry( matrix )
        finally:
            glPopMatrix()

    '''=Rendering Light Depth Texture=

    The depth texture is created by rendering the scene from the
    point-of-view of the light.  In this version of the tutorial,
    we'll render the depth texture into the Context's regular
    "back" buffer and then copy it into the texture.
    '''
    offset = 1.0
    def renderLightTexture( self, light, mode,direction=None, fov = None, textureKey = None ):
        """Render ourselves into a texture for the given light"""
        '''We're going to render our scene into the depth buffer,
        so we'll explicitly specify the depth operation.  The use
        of GL_LEQUAL means that we can rewrite the same geometry
        to the depth buffer multiple times and (save for floating-point
        artefacts), should see the geometry render each time.
        '''
        glDepthFunc(GL_LEQUAL)
        glEnable(GL_DEPTH_TEST)
        '''Our setupShadowContext method will reset our viewport to match
        the size of the depth-texture we're creating.'''
        glPushAttrib(GL_VIEWPORT_BIT)
        '''We invoke our setupShadowContext method to establish the
        texture we'll use as our target.  This tutorial is just going
        to reset the viewport to a subset of the back-buffer (the regular
        rendering target for OpenGL).  Later tutorials will set up an
        off-screen rendering target (a Frame Buffer Object) by overriding
        this method-call.'''
        texture = self.setupShadowContext(light,mode)
        '''==Setup Scene with Light as Camera==

        The algorithm requires us to set up the scene to render
        from the point of view of our light.  We're going to use
        a pair of methods on the light to do the calculations.
        These do the same calculations as "gluPerspective" for
        the viewMatrix, and a pair of rotation,translation
        transformations for the model-view matrix.

        Note:

            For VRML97 scenegraphs, this wouldn't be sufficient,
            as we can have multiple lights, and lights can be children
            of arbitrary Transforms, and can appear multiple times
            within the same scenegraph.

            We would have to calculate the matrices for each path that
            leads to a light, not just for each light. The node-paths
            have methods to retrieve their matrices, so we would simply
            dot those matrices with the matrices we retrieve here.

            The complexity of supporting these features doesn't
            particularly suit an introductory tutorial.
        '''
        if fov:
            cutoff = fov /2.0
        else:
            cutoff = None
        lightView = light.viewMatrix(
            cutoff, near=.3, far=30.0
        )
        lightModel = light.modelMatrix( direction=direction )
        '''The texture matrix translates from camera eye-space into
        light eye-space.  See the original tutorial for an explanation
        of how the mapping is done, and how it interacts with the
        current projection matrix.

        Things to observe about the calculation of the matrix compared
        to the values in the original tutorial:

         * we are explicitly taking the transpose of the result matrix
         * the order of operations is the reverse of the calculations in
           the tutorial
         * we take the transpose of the matrix so that matrix[0] is a row
           in the sense that the tutorial uses it

        This pattern of reversing order-of-operations and taking the
        transpose happens frequently in PyOpenGL when working with matrix
        code from C sources.

        Note:

            A number of fixes to matrix multiply order came from
            comparing results with [http://www.geometrian.com/Programs.php Ian Mallett's OpenGL Library v1.4].
        '''
        lightMatrix = dot( lightModel, lightView )
        textureMatrix = transpose(
            dot(
                lightMatrix,
                self.BIAS_MATRIX
            )
        )
        '''This is a bit wasteful, as we've already loaded our
        projection and model-view matrices for our view-platform into
        the GL.  Real-world implementations would normally do the
        light-rendering pass before doing their world-view setup.
        We'll restore the platform values later on.
        '''
        glMatrixMode( GL_PROJECTION )
        glLoadMatrixf( lightView )
        glMatrixMode( GL_MODELVIEW )
        glLoadMatrixf( lightModel )
        
        '''Our geometryPasses object needs to have the same setup as the
        mode (another FlatPass instance) which we are processing.'''
        self.geometryPasses.matrix = lightModel
        self.geometryPasses.modelView = lightModel
        self.geometryPasses.projection = lightView
        self.geometryPasses.viewport = mode.viewport
        self.geometryPasses.calculateFrustum()
        
        self.geometryPasses.context = self
        self.geometryPasses.cache = mode.cache
        
        try:
            '''Because we *only* care about the depth buffer, we can mask
            out the color buffer entirely. We can use frustum-culling
            to only render those objects which intersect with the light's
            frustum (this is done automatically by the render-visiting code
            we use for drawing).

            Note:
                The glColorMask call does not prevent OpenGL from ever
                attempting to write to the color buffer, it just masks
                regular drawing operations.  A call to glClear() for
                instance, could still clear the colour buffer.
            '''
            if not self.lightViewDebug:
                glColorMask( 0,0,0,0 )
            '''We reconfigure the mode to tell the geometry to optimize its
            rendering process, for instance by disabling normal
            generation, and excluding color and texture information.'''
            self.geometryPasses.lighting = False
            self.geometryPasses.textured = False
            self.geometryPasses.visible = False
            '''==Offset Polygons to avoid Artefacts==

            We want to avoid depth-buffer artefacts where the front-face
            appears to be ever-so-slightly behind itself due to multiplication
            and transformation artefacts.  The original tutorial uses
            rendering of the *back* faces of objects into the depth buffer,
            but with "open" geometry such as the Utah Teapot, we wind up with
            nasty artefacts where e.g. the area on the body around the spout
            isn't shadowed because there's no back-faces in front of it.

            Even with the original approach, using a polygon offset will tend
            to avoid "moire" effects in the shadows where precision issues
            cause the depths in the buffer to pass back and forth across the
            LEQUAL threshold as they cross the surface of the object.

            To avoid these problems, we use a polygon-offset operation.
            The first 1.0 gives us the raw fragment depth-value, the
            second 1.0, the parameter "units" says to take 1.0
            depth-buffer units and add it to the depth-value
            from the previous step, making the depth buffer record values
            1.0 units less than the geometry's natural value.
            '''
            glEnable(GL_POLYGON_OFFSET_FILL)
            glPolygonOffset(1.0, self.offset)
            '''Don't render front-faces, so that we avoid moire effects in 
            the rendering of shadows'''
            glCullFace(GL_FRONT)
            glEnable( GL_CULL_FACE )
            '''And now we draw our scene into the depth-buffer.'''
            self.drawScene( mode, lightModel )
            '''Our closeShadowContext will copy the current depth buffer
            into our depth texture and deactivate the texture.'''
            self.closeShadowContext( texture )

            '''Return the configured texture into which we will render'''
            return texture, textureMatrix
        finally:
            '''Restore "regular" rendering...'''
            glDisable(GL_POLYGON_OFFSET_FILL)
            glShadeModel( GL_SMOOTH )
            glCullFace(GL_BACK)
            glDisable( GL_CULL_FACE )
            glColorMask( 1,1,1,1 )
            '''Now restore the viewport.'''
            glPopAttrib()
    '''The setup of the bias matrix was discussed at some length in the original
    tutorial.  In sum, the depth-buffer is going to return values in the -1 to 1
    range, while the texture has values in range 0-1.  The bias matrix simply maps
    from -1 to 1 to 0 to 1.  We multiply this by the "raw" translation matrix
    to get the final texture matrix which translates from camera eye coordinates
    to texture clip coordinates.'''
    BIAS_MATRIX = array([
        [0.5, 0.0, 0.0, 0.0],
        [0.0, 0.5, 0.0, 0.0],
        [0.0, 0.0, 0.5, 0.0],
        [0.5, 0.5, 0.5, 1.0],
    ], 'f')
    '''==Generating the Depth-Texture==

    Depth texture sizes can have a large effect on the quality
    of the shadows produced.  If your texture only has a couple of dozen
    pixels covering a particular piece of geometry then the shadows on that
    piece of geometry are going to be extremely pixelated.  This is
    particularly so if your light has a wide-angle cutoff.  As more of the
    scene is rendered into the texture, each object covers fewer pixels.
    '''
    shadowMapSize = 512
    textureCacheKey = 'shadowTexture'
    def setupShadowContext( self, light=None, mode=None ):
        """Create a shadow-rendering context/texture"""
        shadowMapSize = self.shadowMapSize
        '''We don't want to re-generate the depth-texture for every frame,
        so we want to keep a cached version of it around.  OpenGLContext has
        an explicit caching mechanism which allows us to check and store the
        value easily.  The cache can hold different elements for a single node,
        so we use a cache key to specify that we're storing the shadow texture
        for the node.'''
        texture = mode.cache.getData(light,key=self.textureCacheKey)
        if not texture:
            '''We didn't find the texture in the cache, so we need to generate it.

            We create a single texture and tell OpenGL to make it the current
            2D texture.
            '''
            texture = glGenTextures( 1 )
            glBindTexture( GL_TEXTURE_2D, texture )
            '''The use of GL_DEPTH_COMPONENT here marks the use of the
            ARB_depth_texture extension.  The GL_DEPTH_COMPONENT constant
            tells OpenGL to use the current OpenGL bit-depth as the format
            for the texture.  So if our context has a 16-bit depth channel,
            we will use that.  If it uses 24-bit depth, we'll use that.

            The None at the end of the argument list tells OpenGL not to
            initialize the data, i.e. not to read it from anywhere.
            '''
            glTexImage2D(
                GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
                shadowMapSize, shadowMapSize, 0,
                GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, None
            )
            '''Now we store the texture in the cache for later passes.'''
            holder = mode.cache.holder( light,texture,key=self.textureCacheKey)
        '''These parameters simply keep us from doing interpolation on the
        data-values for the texture.  If we were to use, for instance
        GL_LINEAR interpolation, our shadows would tend to get "moire"
        patterns.  The cutoff threshold for the shadow would get crossed
        halfway across each shadow-map texel as the neighbouring pixels'
        values were blended.'''
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        '''We assume here that shadowMapSize is smaller than the size
        of the viewport.  Real world implementations would normally
        render to a Frame Buffer Object (off-screen render) to an
        appropriately sized texture, regardless of screen size, falling
        back to this implementation *only* if there was no FBO support
        on the machine.  We will develop the FBO-based rendering in the
        next tutorial.
        '''
        glViewport( 0,0, shadowMapSize, shadowMapSize )
        
        return texture
    def closeShadowContext( self, texture ):
        """Close our shadow-rendering context/texture"""
        '''This is the function that actually copies the depth-buffer into
        the depth-texture we've created.  The operation is a standard OpenGL
        glCopyTexSubImage2D, which is performed entirely "on card", so
        is reasonably fast, though not as fast as having rendered into an
        FBO in the first place.  We'll look at that in the next tutorial.
        '''
        shadowMapSize = self.shadowMapSize
        glBindTexture(GL_TEXTURE_2D, texture)
        glCopyTexSubImage2D(
            GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize
        )
        return texture
    '''=Render Ambient-lit Geometry=

    Our second rendering pass draws the ambient light to the scene.  It
    also fills in the depth buffer which will filter out geometry which
    is behind shadowed geometry which would otherwise "bleed through".
    '''
    def renderAmbient( self, mode ):
        """Render ambient-only lighting for geometry"""
        '''Again, we configure the mode to tell the geometry how to
        render itself.  Here we want to have almost everything save
        the diffuse lighting calculations performed.'''
        self.geometryPasses.context = self
        self.geometryPasses.cache = mode.cache
        
        self.geometryPasses.visible = True
        self.geometryPasses.lighting = True
        self.geometryPasses.lightingAmbient = True
        self.geometryPasses.lightingDiffuse = False
        self.geometryPasses.textured = True
        
        '''As with the geometry, the light will respect the mode's
        parameters for lighting.'''
        for i,light in enumerate( self.lights ):
            light.Light( GL_LIGHT0+i, mode=self.geometryPasses )
        self.drawScene( mode, mode.getModelView() )
    '''=Render Diffuse/Specular Lighting Filtered by Shadow Map=

    This rendering pass is where the magic of the shadow-texture algorithm
    happens.  Our process looks like this:

        * configure the GL to synthesize texture coordinates in
          eye-linear space (the camera's eye coordinate space)
        * load our texture matrix into the "eye planes" of the texture
          coordinate pipeline, there they serve to transform the
          texture coordinates into the clip-space coordinates of the
          depth texture
        * configure the GL to generate an "alpha" value by comparing
          the "R" (Z) component of the generated texture coordinates
          to the Z component stored in the depth-texture.  That is,
          generate a 1.0 alpha where the camera-Z component is
          less-than-or-equal-to the depth in the depth texture.
        * configure the GL to only pass fragments where the alpha is
          greater than .99
    '''
    def renderDiffuse( self, light, texture, textureMatrix, mode, id=0 ):
        """Render lit-pass for given light"""
        '''If we were to turn *off* ambient lighting, we would find that
        our shadowed geometry would be darker whereever there happened
        to be a hole in the geometry through which light was hitting
        (the back of) the geometry.  With fully closed geometry, not
        a problem, but a problem for our Teapot object.  We could solve
        this with a blend operation which only blended brighter pixels,
        but simply re-calculating ambient lighting in this pass is about
        as simple.
        '''
        self.geometryPasses.lightingAmbient = False
        self.geometryPasses.lightingDiffuse = True
        
        '''Again, the light looks at the mode parameters to determine how
        to configure itself.'''
        light.Light( GL_LIGHT0 + id, mode=self.geometryPasses )
        texGenData = [
            (GL_S,GL_TEXTURE_GEN_S,textureMatrix[0]),
            (GL_T,GL_TEXTURE_GEN_T,textureMatrix[1]),
            (GL_R,GL_TEXTURE_GEN_R,textureMatrix[2]),
            (GL_Q,GL_TEXTURE_GEN_Q,textureMatrix[3]),
        ]
        for token,gen_token,row in texGenData:
            '''We want to generate coordinates as a linear mapping
            with each "eye plane" corresponding to a row of our
            translation matrix.  We're going to generate texture
            coordinates that are linear in the eye-space of the
            camera and then transform them with the eye-planes
            into texture-lookups within the depth-texture.'''
            glTexGeni(token, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)
            glTexGenfv(token, GL_EYE_PLANE, row )
            glEnable(gen_token)
        '''Now enable our light's depth-texture, created above.'''
        glBindTexture(GL_TEXTURE_2D, texture)
        glEnable(GL_TEXTURE_2D)
        '''Enable shadow comparison.  "R" here is not "red", but
        the third of 4 texture coordinates, i.e. the transformed
        Z-depth of the generated texture coordinate, now in eye-space
        of the light.'''
        glTexParameteri(
            GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
            GL_COMPARE_R_TO_TEXTURE
        )
        '''Shadow comparison should be true (ie not in shadow)
        if R <= value stored in the texture.  That is, if the
        eye-space Z coordinate multiplied by our transformation
        matrix is at a lower depth (closer) than the depth value
        stored in the texture, then that coordinate is "in the light".
        '''
        glTexParameteri(
            GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL
        )
        '''I don't see any real reason to prefer ALPHA versus
        INTENSITY for the generated values, but I like the symetry
        of using glAlphaFunc with Alpha values.  The original tutorial
        used intensity values, however, so there may be some subtle
        reason to use them.'''
        glTexParameteri(
            GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_ALPHA
        )
        '''Accept anything as "lit" which gives this value or greater.'''
        glAlphaFunc(GL_GEQUAL, .99)
        glEnable(GL_ALPHA_TEST)
        try:
            return self.drawScene( mode, mode.getModelView() )
        finally:
            '''Okay, so now we need to do cleanup and get back to a regular
            rendering mode...'''
            glDisable(GL_TEXTURE_2D)
            for _,gen_token,_ in texGenData:
                glDisable(gen_token)
            glDisable(GL_LIGHTING)
            glDisable(GL_LIGHT0+id)
            glDisable(GL_ALPHA_TEST)
            mode.lightingAmbient = True
            glTexParameteri(
                GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
                GL_NONE
            )
    def OnInit( self ):
        """Do all of our setup functions..."""
        BaseContext.OnInit( self )
        print """You should see something that looks vaguely like
a water-fountain, with individual droplets starting
blue and turning white."""
        '''The PointSet node will do the actual work of rendering 
        our points into the GL.  We start it off with all points 
        at the emitter location and with initial colour.'''
        self.points = PointSet(
            coord = Coordinate(
                point = [emitter]*count
            ),
            color = Color(
                color = [initialColor]*count
            ),
            minSize = 7.0,
            maxSize = 10.0,
            attenuation = [0,1,0],
        )
        '''We use a simple Appearance node to apply a texture to the 
        PointSet, the PointSet will use this to enable sprite-based 
        rendering if the extension(s) are available.'''
        self.shape = Shape(
            appearance = Appearance(
                texture = ImageTexture( url='_particle.png' ),
            ),
            geometry = self.points,
        )
        self.text = Text(
            string = ["""Current multiplier: 1.0"""],
            fontStyle = FontStyle(
                family='SANS', format = 'bitmap',
                justify = 'MIDDLE',
            ),
        )
        self.sg = sceneGraph( children = [
            self.shape,
            SimpleBackground( color = (.5,.5,.5),),
            Transform(
                translation = (0,-1,0),
                children = [
                    Shape(
                        geometry = self.text
                    ),
                ],
            ),
        ] )
        self.velocities = array([ (0,0,0)]*count, 'd')
        self.colorVelocities = array( colorVelocities, 'd')
        print '  <s> make time pass more slowly'
        print '  <f> make time pass faster'
        print '  <h> higher'
        print '  <l> (L) lower'
        print '  <[> smaller drops'
        print '  <]> larger drops'
        self.addEventHandler( "keypress", name="s", function = self.OnSlower)
        self.addEventHandler( "keypress", name="f", function = self.OnFaster)
        self.addEventHandler( "keypress", name="h", function = self.OnHigher)
        self.addEventHandler( "keypress", name="l", function = self.OnLower)
        self.addEventHandler( "keypress", name="]", function = self.OnLarger)
        self.addEventHandler( "keypress", name="[", function = self.OnSmaller)
        '''First timer will provide the general simulation heartbeat.'''
        self.time = Timer( duration = 1.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        '''Second timer provides a cycle on which the fountain 
        reduces/increases the speed at which droplets are started.'''
        self.time2 = Timer( duration = 5.0, repeating = 1 )
        self.time2.addEventHandler( "cycle", self.OnLower )
        self.time2.register (self)
        self.time2.start ()
class TestContext(BaseContext):
    """
    Demonstrates use of attribute types in GLSL
    """

    def get_lights(self):
        light1 = self.angle + np.pi * 1.2
        light2 = self.angle + np.pi * 1.8
        light_nodes = [
            N.DirectionalLight(
                color=(.1, .8, 0),
                intensity=0.8,
                ambientIntensity=0.1,
                direction=(np.cos(light1), np.sin(light1), -1),
            ),
            N.DirectionalLight(
                color=(.1, .8, 0),
                intensity=0.4,
                ambientIntensity=0.1,
                direction=(np.cos(light2), np.sin(light2), -1),
            ),
            # N.SpotLight(
            #     location=(0.5, 0.5, 1),
            #     color=(1, 1, 1),
            #     ambientIntensity=.1,
            #     attenuation=(0, 0, 1),
            #     beamWidth=np.pi*0.2,
            #     cutOffAngle=np.pi*.9,
            #     direction=(0, 0, -1),
            #     intensity=.5,
            # ),
            # N.PointLight(
            #     location=(0.5, 0.5, 0.2),
            #     color=(0.5, 0.5, 0.5),
            #     intensity=.1,
            #     ambientIntensity=0,
            #     attenuation=(0, .5, 0),
            # ),
        ]
        return [self.light_node_as_struct(l) for l in light_nodes]

    def OnInit(self):
        self.angle = 0

        shader_common = read_shader(
            'shader_common.h', D={'NLIGHTS': len(self.get_lights())})

        phong_weightCalc = read_shader('phong_weightCalc.h')
        phong_preCalc = read_shader('phong_preCalc.h')

        light_preCalc = read_shader('light_preCalc.h')

        self.shader = Shader.compile(
            shader_common + phong_preCalc + light_preCalc +
            read_shader('vertex.h'),
            shader_common + phong_weightCalc +
            read_shader('fragment.h'))

        self.time = Timer(duration=20.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()

        self.set_terrain_ttd()

        self.vw = self.vh = 300

    def OnResize(self, *args):
        self.vw, self.vh = args
        super().OnResize(*args)

    def set_view(self):
        G.glMatrixMode(G.GL_MODELVIEW)
        center = np.array([0.5, 0.5, 0])
        radius = 4.5
        v = np.pi * 0.2
        eye = (center +
               radius *
               np.array([np.cos(self.angle), np.sin(self.angle), 1]) *
               np.array([np.cos(v), np.cos(v), np.sin(v)]))
        eyeX, eyeY, eyeZ = eye
        centerX, centerY, centerZ = center
        upX, upY, upZ = 0, 0, 1
        G.glLoadIdentity()
        GLU.gluLookAt(eyeX, eyeY, eyeZ,
                      centerX, centerY, centerZ,
                      upX, upY, upZ)

        G.glMatrixMode(G.GL_PROJECTION)
        G.glLoadIdentity()
        vfov = self.vh / 150
        if vfov > 10:
            vfov = 10 * (1 + np.log(vfov / 10))
        GLU.gluPerspective(vfov, self.vw / self.vh, 0.1, 100)

    def load_terrain(self):
        t1 = time.time()
        heights = np.asarray(
            PIL.Image.open('/home/rav/rasters/ds11.tif').convert('F'))
        t2 = time.time()
        print("Reading heights took %.4f s" % (t2 - t1,))
        return heights[:200, :200]

    def set_terrain_mc(self):
        heights = self.load_terrain()
        t2 = time.time()
        # quads[i] is [norm, a, b, c, d],
        # abcd right-handed counter-clockwise around norm
        quads = []
        for y, row in enumerate(heights):
            for x, z in enumerate(row):
                norm = [0, 0, 1]
                quads.append(
                    ([0, 0, 1],
                     [x, y, z],
                     [x + 1, y, z],
                     [x + 1, y + 1, z],
                     [x, y + 1, z]))
                z2 = heights[y, x + 1] if x + 1 < len(row) else 0
                if z2 < z:
                    quads.append(
                        ([1, 0, 0],
                         [x + 1, y, z],
                         [x + 1, y, z2],
                         [x + 1, y + 1, z2],
                         [x + 1, y + 1, z]))
                z2 = heights[y, x - 1] if x > 0 else 0
                if z2 < z:
                    quads.append(
                        ([-1, 0, 0],
                         [x, y + 1, z2],
                         [x, y, z2],
                         [x, y, z],
                         [x, y + 1, z]))
                z2 = heights[y + 1, x] if y + 1 < len(heights) else 0
                if z2 < z:
                    quads.append(
                        ([0, 1, 0],
                         [x + 1, y + 1, 0],
                         [x, y + 1, 0],
                         [x, y + 1, z],
                         [x + 1, y + 1, z]))
                z2 = heights[y - 1, x] if y > 0 else 0
                if z2 < z:
                    quads.append(
                        ([0, -1, 0],
                         [x, y, z],
                         [x, y, 0],
                         [x + 1, y, 0],
                         [x + 1, y, z]))
        t3 = time.time()
        print("Creating %s quads from %s cells took %.4f s" % (len(quads), len(heights.ravel()), t3 - t2))
        vertices = []
        normals = []
        indices = []
        for norm, a, b, c, d in quads:
            ai, bi, ci, di = range(len(vertices), len(vertices) + 4)
            vertices += [a, b, c, d]
            normals += 4*[norm]
            indices += [
                ai, bi, di,
                bi, ci, di,
            ]
        vertices = np.asarray(vertices)
        self.normalize_vertices(vertices)
        v = list(zip(vertices, normals))
        t4 = time.time()
        print("Post-processing quads took %.4f s" % (t4 - t3,))
        self.shader.set_vertices(v, indices)
        t5 = time.time()
        print("set_vertices took %.4f s" % (t5 - t4,))

    def set_terrain_ttd(self):
        heights = self.load_terrain()

        ys, xs = np.indices(heights.shape)
        xyz = np.dstack((xs, ys, heights))
        aa = xyz[:-1, :-1]
        bb = xyz[:-1, 1:]
        cc = xyz[1:, 1:]
        dd = xyz[1:, :-1]
        # ac[y, x] and bd[y, x] are the two ways of triangulating the
        # [x, x+1]*[y, y+1] quad
        bd = np.concatenate((aa, bb, dd, bb, cc, dd), axis=2)
        ac = np.concatenate((aa, cc, dd, aa, bb, cc), axis=2)

        # bd_lower[y, x] is true if the bd diagonal is lower than ac
        bd_lower = aa[:, :, 2] + cc[:, :, 2] > bb[:, :, 2] + dd[:, :, 2]
        # ts[y, x, :] is the triangulation of the [x, x+1]*[y, y+1] quad
        # with the lower diagonal.
        ts = np.choose(bd_lower[:, :, np.newaxis], (ac, bd))
        # Number of triangles = 2 * number of quads
        nts = 2 * ts.shape[0] * ts.shape[1]
        # Reshape to list of triangles
        ts = ts.reshape((nts, 9))
        # Compute the surface normals
        p1 = ts[:, 0:3]
        p2 = ts[:, 3:6]
        p3 = ts[:, 6:9]
        n = np.cross(p2 - p1, p3 - p1)  # surface normals
        # Turn into list of (point xyz, normal xyz)
        v = np.c_[p1, n, p2, n, p3, n].reshape(3 * nts, 2, 3)
        # Normalize all point xyz
        self.normalize_vertices(v[:, 0, :])
        self.shader.set_vertices(v)

    def normalize_vertices(self, vertices):
        vmin = vertices.min(axis=0, keepdims=True)
        vmax = vertices.max(axis=0, keepdims=True)
        vertices[:] = (vertices - vmin) / (vmax - vmin)
        vertices[:, 2] -= 0.5
        vertices[:, 2] /= (vmax[0, 2] - vmin[0, 2]) / 40

    def Render(self, mode=0):
        """Render the geometry for the scene."""
        super().Render(mode)
        with self.shader:
            for name, val in [
                ('Global_ambient', (.2, .2, .2, 1.0)),
                ('material_ambient', (.5, .8, .5, 1.0)),
                ('material_diffuse', (.2, .8, .2, 1.0)),
                ('material_specular', (.05, .05, .05, 1.0)),
                ('material_shininess', (1,)),
            ]:
                self.shader.setuniform(name, val)
            lights = self.get_lights()
            for k in Light._fields:
                self.shader.setuniforms(
                    'lights_' + k, [getattr(l, k) for l in lights])
            self.set_view()
            self.shader.draw()

    def light_node_as_struct(self, light):
        """Given a single VRML97 light-node, produce light value array"""
        if not light.on:
            z = np.zeros(len(Light._fields), 4)
            return Light(*z)
        color = light.color

        def as4(v, w=1.0):
            return np.asarray(list(v) + [w])

        if isinstance(light, N.DirectionalLight):
            position = -as4(light.direction, 0)
            attenuation = spot = spotdir = np.zeros(4)
        else:
            position = as4(light.location)
            attenuation = as4(light.attenuation)
            if isinstance(light, N.SpotLight):
                spot = [np.cos(light.beamWidth / 4),
                        light.cutOffAngle / light.beamWidth,
                        0, 1.0]
                spotdir = as4(light.direction)
            else:
                spot = spotdir = np.zeros(4)

        return Light(
            ambient=as4(color * light.ambientIntensity),
            diffuse=as4(color * light.intensity),
            specular=as4(color * light.intensity),
            position=position,
            attenuation=attenuation,
            spot=spot,
            spotdir=spotdir,
        )

    def OnTimerFraction(self, event):
        frac = event.fraction()
        self.angle = 2 * np.pi * frac
        self.triggerRedraw()
Exemple #45
0
 def OnInit( self ):
     """Load the image on initial load of the application"""
     print """Each dot is a request (y shows data transferred)"""
     self.log_queue = Queue.Queue( maxsize=self.dataPoints )
     self.coordinate = Coordinate(
         point = [(0,0,0)]*self.dataPoints,
     )
     # should *not* be necessary, but is, to prevent a cached 
     # bounding volume from dropping the graph
     boundingvolume.cacheVolume(
         self.coordinate,
         boundingvolume.UnboundedVolume(),
     )
     # just an arbitrary format/style for the text
     self.fontstyle = FontStyle(
         family='SANS', format = 'bitmap',
         justify = 'BEGIN',
     )
     #
     self.color = Color(
         color = [1.0,0.0,0.0],
     )
     self.data_slider = Transform(
         translation=(0,0,0),
         scale = (1/600.,1,1,),
         children = [
             Shape(
                 appearance = Appearance(
                     texture = ImageTexture( url='_particle.png' ),
                     material = Material(
                         diffuseColor = [1,0,0],
                     )
                 ),
                 geometry = PointSet(
                     coord = self.coordinate,
                     minSize = 5.0,
                     maxSize = 5.0,
                 ),
             ),
         ],
     )
     self.axes = Transform(
         children = [
             Transform( 
                 translation = (.25,coord,0),
                 children = [
                     Shape( geometry = Text(
                         string = [label],
                         fontStyle = self.fontstyle,
                     ))
                 ],
             )
             for (coord,label) in [
                 (0,'0B'),
                 (3,'1KB'),
                 (6,'1MB'),
                 (9,'1GB'),
             ]
         ] + [
             Transform( 
                 translation = (coord,-.75,0),
                 children = [
                     Shape( geometry = Text(
                         string = [label],
                         fontStyle = self.fontstyle,
                     ))
                 ],
             )
             for (coord,label)in [
                 (0,'now'),
                 (-1200*self.data_slider.scale[0],'-20m'),
                 (-2400*self.data_slider.scale[0],'-40m'),
                 (-3600*self.data_slider.scale[0],'-60m'),
             ]
         ]
     )
     self.transform = Transform(
         translation = (3,-2,0),
         children = [
             self.data_slider,
             self.axes,
         ]
     )
     self.sg = sceneGraph(
         children = [
             self.transform,
         ],
     )
     self.time = Timer( duration = 1, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
     thread = threading.Thread( target = log_reader, args=('epa-http.txt',self.log_queue))
     thread.setDaemon(True)
     thread.start()
Exemple #46
0
class TestContext( BaseContext ):
    initialPosition = (0,0,10) # set initial camera position, tutorial does the re-positioning
    dataPoints = 3600
    def OnInit( self ):
        """Load the image on initial load of the application"""
        print """Each dot is a request (y shows data transferred)"""
        self.log_queue = Queue.Queue( maxsize=self.dataPoints )
        self.coordinate = Coordinate(
            point = [(0,0,0)]*self.dataPoints,
        )
        # should *not* be necessary, but is, to prevent a cached 
        # bounding volume from dropping the graph
        boundingvolume.cacheVolume(
            self.coordinate,
            boundingvolume.UnboundedVolume(),
        )
        # just an arbitrary format/style for the text
        self.fontstyle = FontStyle(
            family='SANS', format = 'bitmap',
            justify = 'BEGIN',
        )
        #
        self.color = Color(
            color = [1.0,0.0,0.0],
        )
        self.data_slider = Transform(
            translation=(0,0,0),
            scale = (1/600.,1,1,),
            children = [
                Shape(
                    appearance = Appearance(
                        texture = ImageTexture( url='_particle.png' ),
                        material = Material(
                            diffuseColor = [1,0,0],
                        )
                    ),
                    geometry = PointSet(
                        coord = self.coordinate,
                        minSize = 5.0,
                        maxSize = 5.0,
                    ),
                ),
            ],
        )
        self.axes = Transform(
            children = [
                Transform( 
                    translation = (.25,coord,0),
                    children = [
                        Shape( geometry = Text(
                            string = [label],
                            fontStyle = self.fontstyle,
                        ))
                    ],
                )
                for (coord,label) in [
                    (0,'0B'),
                    (3,'1KB'),
                    (6,'1MB'),
                    (9,'1GB'),
                ]
            ] + [
                Transform( 
                    translation = (coord,-.75,0),
                    children = [
                        Shape( geometry = Text(
                            string = [label],
                            fontStyle = self.fontstyle,
                        ))
                    ],
                )
                for (coord,label)in [
                    (0,'now'),
                    (-1200*self.data_slider.scale[0],'-20m'),
                    (-2400*self.data_slider.scale[0],'-40m'),
                    (-3600*self.data_slider.scale[0],'-60m'),
                ]
            ]
        )
        self.transform = Transform(
            translation = (3,-2,0),
            children = [
                self.data_slider,
                self.axes,
            ]
        )
        self.sg = sceneGraph(
            children = [
                self.transform,
            ],
        )
        self.time = Timer( duration = 1, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        thread = threading.Thread( target = log_reader, args=('epa-http.txt',self.log_queue))
        thread.setDaemon(True)
        thread.start()
        
    def OnTimerFraction( self, evt ):
        new = []
        try:
            for i in range(len(self.coordinate.point)):
                new.append( self.log_queue.get( False ) )
        except Queue.Empty:
            pass 
        if not new:
            return
        # TODO: new might be bigger than our buffer, stop that
        to_retain = len(self.coordinate.point)-len(new)
        if to_retain:
            self.coordinate.point[:to_retain] = self.coordinate.point[-to_retain:]
        self.coordinate.point[-len(new):] = new
        # trigger new-bounding-box calculation
        boundingvolume.volumeFromCoordinate( self.coordinate )
        self.coordinate.point = self.coordinate.point
        self.data_slider.translation = -new[-1][0]*self.data_slider.scale[0],0,0
        
        self.triggerRedraw()
Exemple #47
0
class TestContext( BaseContext ):
		
	def OnInit( self ):
		
		self.drawCapture = 0
		self.capturedImage = ()
		self.useStringDraw = 0
		self.reverseShape = 0
		self.capturedImageFormat = GL_RGB
		
		self.planRot = 0;
		self.frameIter = 0;
		
		self.iter = 0
		self.strPos = 0
		self.newSystemTime = 45
		self.systemIterator = 0
		self.uniqueIDs = []
		
		self.whichSTR = 0
		

		glutReshapeWindow( 1400, 850)
		glutPositionWindow( 0, 0 )
		glutFullScreen( )
		
		self.time = Timer( duration = 60.0, repeating = 1 )
		self.time.addEventHandler( "fraction", self.OnTimerFraction )
		self.time.register (self)
		self.time.start ()
		
		#self.updater = Timer(duration = 61, repeating = 1)
		#self.updater.addEventHandler("cycle", self.updateFromSQL )
		#self.updater.register(self)
		#self.updater.start ()
		
		
		self.rot = 0
		
		self.offset = 3
		
		#dragging flag
		self.startDrag = 0
		
		#holder for last detail rendered planet
		self.lastDetail = ()
		
		
		#make some random planets and systems
		#self.universe = universe.Universe()
		
		self.addEventHandler( 'keypress', name='s', function=self.OnSave )
		
		#get fonts
		providers = fontprovider.getProviders( 'solid' )
		if not providers:
			raise ImportError( """NONONO solid font providers registered! Demo won't function properly!""" )
		registry = self.getTTFFiles()
		styles = []
		for font in registry.familyMembers( 'SANS' ):
			names = registry.fontMembers( font, 400, 0)
			for name in names:
				styles.append( fontstyle3d.FontStyle3D(
					family = [name],
					size = .06,
					justify = "LEFT",
					thickness = .02,
					quality = 3,
					renderSides = 1,
					renderFront = 1,
					renderBack = 1,
				))
		self.styles = styles
		
		#render all ascii
		self.ascii = []
		asciiNum = 32
		while asciiNum<128:
			self.ascii.append( basenodes.Text( fontStyle=self.styles[0], string=chr(asciiNum) ) )
			asciiNum += 1
						
				
		####	Starting SQL Integration Here
		self.universe = universe.Universe()
		numSys = 1
		self.universe.addSys(self.systemIterator)
		
		conn = MySQLdb.connect( host = "ec2-75-101-245-127.compute-1.amazonaws.com",
								user = "******",
								passwd = "ohhai",
								db = "wikihole")
		self.stringArray = []
		cursor = conn.cursor()
		cursor.execute( "SELECT * FROM history")
		self.planetMoons = list();
		offsetset = 0
		while (1):
			row = cursor.fetchone()
			if row == None:
				break
			print "%s\t%s\t%s" % (row[0], row[2], row[1])	
			if(not offsetset):
				self.offset = row[0]
				offsetset = 1
				lastTime = "%s" % row[2]
				thisTime = "%s" % row[2]
			else:
				lastTime = thisTime
				thisTime = "%s" % row[2]
			
			if( not gethistory.timeDiff(lastTime, thisTime, self.newSystemTime) ):
				self.systemIterator = self.systemIterator + 1
				self.universe.addSys(self.systemIterator)
				print "MADE NEW SYSTEM"
				#print lastTime
				#print thisTime
			
			url = row[1]
			
			self.uniqueIDs.append(row[0])
			
			imageurls = gethistory.getImageUrls(url)
			
			
			#make geometry array for description
			geom = []
			gNum = 0
			descripStr = gethistory.getDescription(url)
			
			while gNum<200:
				strr = descripStr[ gNum ]  #self.bigString[ gNum ] 
				asciiNumber = ord( strr )-32
				if( not asciiNumber>=0 or not asciiNumber<=95 ):
					asciiNumber = 0
					print "OUTOFBOUNDS"
				geom.append( self.ascii[ asciiNumber ] )
				gNum += 1
				
			if( self.whichSTR == 0):
				self.whichSTR = 1
			else:
				self.whichSTR = 0
				
			print self.whichSTR
							
				
			#render font geom for title
			names = url.split('/')
			wikititle = names[len(names) - 1]
			wikititle = wikititle.replace('_', ' ')
			self.stringArray.append(wikititle)
			title = basenodes.Text( fontStyle=self.styles[0], string=wikititle )
			
			#get list of image urls for planet moons
			fileList = list()
			for image in imageurls:
				linetoExec = "wget " + image

				fullpath = image.split('/')
				existsOrNot =  os.path.exists( fullpath[len(fullpath) - 1] )
				if(existsOrNot):
					fileList.append( fullpath[len(fullpath) - 1] )
				else:
					fileList.append( fullpath[len(fullpath) - 1] )
					os.system(linetoExec)  #uncomment this before real runs
			#self.planetMoons.append(fileList)
			
			####
			#FINALLY add the planet to the current solar system
			self.universe.addPlanet(row[0], len(imageurls), title, geom, fileList)
					

						
		"""Setup callbacks and build geometry for rendering"""
		#on mouse down
		self.addEventHandler( "mousebutton", button = 0, state=1, function = self.mouseDown )
		#on mouse up
		self.addEventHandler( "mousebutton", button = 0, state = 0, function = self.mouseUp )
				
		glutinteractivecontext.GLUTInteractiveContext.setupDefaultEventCallbacks(self)
		
		self.initialPosition = ( 0,0,20 )
		self.STEPDISTANCE = 5.0
		self.newPos = self.initialPosition
		self.goTo = 0
				
		#r = threading.Thread( target = self.randomiser )
		#r.setDaemon(1)
		#r.start()
	

	def OnIdle( self, ):
		#rotate the planets
		self.planRot -= 0.08
		self.universe.rotatePlanets( self.planRot )
		#same the frame to an image
		#self.SaveTo( 'img/movie01_'+str(self.frameIter)+'.png' )
		self.frameIter += 1
		
		if self.goTo:
			self.tweenCam()
		self.triggerRedraw(1)
		return 1
		
	def getSceneGraph( self ):
		return self.universe.uni
		
	def glutOnMouseMove(self, x, y):
		if self.startDrag == 1:
			trackP,trackQ = self.track.update( x,y )
			print "p: ",trackP
			print "q: ",trackQ
			self.platform.setPosition( trackP )
			self.platform.setOrientation( trackQ )
			
	def mouseDown( self, event ):
		#make trackball
		x,y  = event.getPickPoint()
		print "track centerY: ", self.newPos[1]
		self.track = trackball.Trackball( position=self.platform.position, quaternion=self.platform.quaternion, center=(self.newPos[0],self.newPos[1],self.newPos[2]-2), originalX=x, originalY=y, width=800, height=600 )
		self.startDrag = 1
		
	def mouseUp( self, event ):
		"""Handle a mouse-click in our window.
		Retrieves the "pick point", and the unprojected (world-space) coordinates
		of the clicked geometry (if a named object was clicked).
		"""
		
		self.startDrag = 0
		self.track.cancel()
		
		x,y  = event.getPickPoint()
		print 'Click', (x,y)
		
		
		print '  %s objects:'%( len(event.getObjectPaths()))
		for path in event.getObjectPaths():
			#find planet
			foundPlanet = self.universe.findPlanet( path )
			#find solarsys
			foundSys = self.universe.findSys( path )
			
			
			if foundPlanet and foundSys:
				print "found planet:",foundPlanet.choice[0].name, "in sys:", foundSys.name
				#if there is one rendered detailed... put the simple back in
				if self.lastDetail:
					self.universe.unRenderDetail( self.lastDetail )				
					
				#switchbetween levels of detail
				self.lastDetail = foundPlanet
				self.universe.renderDetail( foundPlanet )
				print "RENDRED DETAIL"
				
				#calc the new point in global space
				summedTrans =  foundPlanet.choice[0].translation + foundSys.translation
				self.newPos = ( summedTrans[0], summedTrans[1], summedTrans[2]+1.2 )
				self.goTo = 1
								
								
	def OnClick2( self, event ):
		"""Handle mouse click for a given name/id"""
		print "You clicked on the magic sphere!"
		self.OnClick1( event )


	def setupFontProviders( self ):
		"""Load font providers for the context

		See the OpenGLContext.scenegraph.text package for the
		available font providers.
		"""
		fontprovider.setTTFRegistry(
			self.getTTFFiles(),
		)
	
	def randomiser( self ):
		while self:
			self.lockScenegraph()
			try:
				#rotate all the planets
				#self.universe.rotatePlanets( self.rot )
				self.rot += 0.05
			finally:
				self.unlockScenegraph()
			if self:
				self.triggerRedraw(1)
			time.sleep( .05 )	
			
	def OnTimerFraction( self, event ):
		#self.universe.rotatePlanets( -60*event.fraction() )
		self.iter = self.iter + 1
		#print "awesome! %d" % self.iter
		if(self.iter > 200):  
			self.updateFromSQL()
			self.iter = 0
		
	def tweenCam( self ):
		speed = 0.2
		#move to newPos
		deltaVector = ( self.newPos[0]-self.platform.position[0] , self.newPos[1]-self.platform.position[1], self.newPos[2]-self.platform.position[2] )
		deltaInc = ( deltaVector[0]*speed,deltaVector[1]*speed,deltaVector[2]*speed )
		self.platform.moveRelative( x=deltaInc[0],y=deltaInc[1],z=deltaInc[2] )
	
		#look at newPos
		#set orientation back to initial default 
		self.platform.setOrientation( (0,1,0,0) )
		#calc dela ang about y axis
		dx = self.platform.position[0] - self.newPos[0]
		dy = self.platform.position[1] - self.newPos[1]
		dz = self.platform.position[2] - self.newPos[2]
		#compute axis rotation angles
		yAng = math.atan( dx/dz )
		xAng = math.atan( dy/dz )
		#apply turn on y axis
		self.platform.turn( (0,1,0,yAng*speed) )
		#apply turn to x axis
		self.platform.turn( (1,0,0,-xAng*speed) )
		
		avgDist = math.fabs(deltaInc[0]+deltaInc[1]+deltaInc[2])/3
		if( avgDist < 0.001 ):
			self.goTo = 0
			
	def updateFromSQL(self):
		print "ACTUALLY CALLED updateFromSQL!!! wohoo!!!\n"
		largestRecord = -12
		for ident in self.uniqueIDs:
			if(ident > largestRecord):
				largestRecord = ident
		
		
		conn = MySQLdb.connect( host = "ec2-75-101-245-127.compute-1.amazonaws.com",
								user = "******",
								passwd = "ohhai",
								db = "wikihole")
								
		cursor = conn.cursor()
		cursor.execute("SELECT * FROM history WHERE id = %d" % largestRecord)
		row = cursor.fetchone()
		lastHighest = "%s" % row[2]
		

		
		
		cursor = conn.cursor()
		cursor.execute( "SELECT * FROM history WHERE id > %d" % largestRecord)
		
		print "checking for records larger than %d" % largestRecord
		first = 1
		while (1):
			row = cursor.fetchone()
			if row == None:
				break
			print "%s\t%s\t%s" % (row[0], row[2], row[1])	
			if(first):
				lastTime = lastHighest
				thisTime = "%s" % row[2]
				first = 0
			else:
				lastTime = thisTime
				thisTime = "%s" % row[2]

			if( not gethistory.timeDiff(lastTime, thisTime, self.newSystemTime) ):
				self.systemIterator = self.systemIterator + 1
				self.universe.addSys(self.systemIterator)
				print "MADE NEW SYSTEM"
				#print lastTime
				#print thisTime
			url = row[1]
			self.uniqueIDs.append(row[0])
			imageurls = gethistory.getImageUrls(url)

			#render font geom for title
			names = url.split('/')
			wikititle = names[len(names) - 1]
			wikititle = wikititle.replace('_', ' ')
			self.stringArray.append(wikititle)
			title = basenodes.Text( fontStyle=self.styles[0], string=wikititle )

			#make geometry array for description
			geom = []
			gNum = 0
			descripStr = gethistory.getDescription(url)
			
			while gNum<200:
				strr = descripStr[ gNum ]  #self.bigString[ gNum ] 
				asciiNumber = ord( strr )-32
				if( not asciiNumber>=0 or not asciiNumber<=95 ):
					asciiNumber = 0
					print "OUTOFBOUNDS"
				geom.append( self.ascii[ asciiNumber ] )
				gNum += 1

			fileList = list()
			#do this stuff in a thread
			for image in imageurls:
				linetoExec = "wget " + image
				fullpath = image.split('/')
				fileList.append( fullpath[len(fullpath) - 1] )
				os.system(linetoExec)  #uncomment this before real runs
				
				self.planetMoons.append(fileList)

			#self.universe.addPlanet(row[0], len(imageurls))
			self.universe.addPlanet(row[0], len(imageurls), title, geom, fileList)
			names = url.split('/')
			wikititle = names[len(names) - 1]
			wikititle = wikititle.replace('_', ' ')
			self.stringArray.append(wikititle)
			
			
			
	
	def OnSave( self, event=None):
		self.SaveTo( 'img/test.png' )
	def SaveTo( self, filename, format="PNG" ):
		import Image
		if not len(self.capturedImage):
			self.OnCaptureColour()
		data = self.capturedImage
		if self.capturedImageFormat == GL_RGB:
			pixelFormat = 'RGB'
		else:
			pixelFormat = 'L'
		width,height,depth = self.capturedSize
		image = Image.fromstring( pixelFormat, (int(width),int(height)), data.tostring() )
		image = image.transpose( Image.FLIP_TOP_BOTTOM)
		image.save( filename, format )
		print 'Saved image to %s'% (os.path.abspath( filename))
		self.capturedImage = ()
		return image
	def OnCaptureColour( self , event=None):
		import Image # get PIL's functionality...
		width, height = self.getViewPort()
		glPixelStorei(GL_PACK_ALIGNMENT, 1)
		data = glReadPixelsub(0, 0, width, height, GL_RGB)
		assert data.shape == (width,height,3), """Got back array of shape %r, expected %r"""%(
			data.shape,
			(width,height,3),
		)
		string = data.tostring()
		print 'array returned was', data.shape
		if self.reverseShape:
			data.shape = (height,width,3)
			print 'reversed shape', data.shape
		assert data.tostring() == string, """Data stored differs in format"""
		self.capturedImage = data
		self.capturedImageFormat = GL_RGB
		self.capturedSize = (width,height,3)
class TestContext(BaseContext):
	"""Demonstrates the use of attribute types in GLSL"""

	def OnInit(self):
		"""Initialize the context"""
		vertex_shader = shaders.compileShader(
			"""
			uniform float tween;
			attribute vec3 position;
			attribute vec3 tweened;
			attribute vec3 color;
			varying vec4 baseColor;
			void main()
			{
				gl_Position = gl_ModelViewProjectionMatrix
					* mix(vec4(position, 1.0), vec4(tweened, 1.0), tween);
				baseColor = vec4(color, 1.0);
			}
			""",
			GL_VERTEX_SHADER)
		fragment_shader = shaders.compileShader(
			"""
			varying vec4 baseColor;
			void main()
			{
				gl_FragColor = baseColor;
			}
			""",
			GL_FRAGMENT_SHADER)
		self.shader = shaders.compileProgram(vertex_shader, fragment_shader)
		self.vbo = vbo.VBO(
			array([
				[0, 1, 0, 1, 3, 0, 0, 1, 0],
				[-1, -1, 0, -1, -1, 0, 1, 1, 0],
				[1, -1, 0, 1, -1, 0, 0, 1, 1],
				[2, -1, 0, 2, -1, 0, 1, 0, 0],
				[4, -1, 0, 4, -1, 0, 0, 1, 0],
				[4, 1, 0, 4, 9, 0, 0, 0, 1],
				[2, -1, 0, 2, -1, 0, 1, 0, 0],
				[4, 1, 0, 1, 3, 0, 0, 0, 1],
				[2, 1, 0, 1, -1, 0, 0, 1, 1]
				], "f"))
		self.position_location = glGetAttribLocation(self.shader, "position")
		self.tweened_location = glGetAttribLocation(self.shader, "tweened")
		self.color_location = glGetAttribLocation(self.shader, "color")
		self.tween_location = glGetUniformLocation(self.shader, "tween")
		self.time = Timer(duration=2.0, repeating=1)
		self.time.addEventHandler("fraction", self.OnTimerFraction)
		self.time.register(self)
		self.time.start()

	def Render(self, mode=0):
		"""Render the geometry for the scene."""
		super(TestContext, self).Render(mode)
		glUseProgram(self.shader)
		glUniform1f(self.tween_location, self.tween_fraction)
		try:
			self.vbo.bind()
			try:
				glEnableVertexAttribArray(self.position_location)
				glEnableVertexAttribArray(self.tweened_location)
				glEnableVertexAttribArray(self.color_location)
				stride = 4 * 9
				glVertexAttribPointer(
					self.position_location, 
					3, GL_FLOAT, False, stride, self.vbo)
				glVertexAttribPointer(
					self.tweened_location, 
					3, GL_FLOAT, False, stride, self.vbo + 12)
				glVertexAttribPointer(
					self.color_location, 
					3, GL_FLOAT, False, stride, self.vbo + 24)
				glDrawArrays(GL_TRIANGLES, 0, 9)
			finally:
				self.vbo.unbind()
				glDisableVertexAttribArray(self.position_location)
				glDisableVertexAttribArray(self.tweened_location)
				glDisableVertexAttribArray(self.color_location)
		finally:
			shaders.glUseProgram(0)

	tween_fraction = 0.0

	def OnTimerFraction(self, event):
		frac = event.fraction()
		if frac > 0.5:
			frac = 1.0 - frac
		frac *= 2
		self.tween_fraction = frac
		self.triggerRedraw()
    def OnInit( self ):
        """Initialize the context"""
        '''== Phong and Blinn Reflectance ==

        A shiny surface will tend to have a "bright spot" at the point 
        on the surface where the angle of incidence for the reflected
        light ray and the viewer's ray are (close to) equal.  
        A perfect mirror would have the brights spot solely when the 
        two vectors are exactly equal, while a perfect Lambertian
        surface would have the "bright spot" spread across the entire
        surface.
        
        The Phong rendering process models this as a setting, traditionally
        called material "shininess" in Legacy OpenGL.  This setting acts 
        as a power which raises the cosine (dot product) of the 
        angle between the reflected ray and the eye.  The calculation of 
        the cosine (dot product) of the two angles requires that we do 
        a dot product of the two angles once for each vertex/fragment 
        for which we wish to calculate the specular reflectance, we also 
        have to find the angle of reflectance before we can do the 
        calculation:'''
        """
            L_dir = (V_pos-L_pos)
            R = 2N*(dot( N, L_dir))-L_dir
            // Note: in eye-coordinate system, Eye_pos == (0,0,0)
            Spec_factor = pow( dot( R, V_pos-Eye_pos ), shininess)
        """
        '''which, as we can see, involves the vertex position in a number 
        of stages of the operation, so requires recalculation all through 
        the rendering operation.
        
        There is, however, a simplified version of Phong Lighting called 
        [http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model Blinn-Phong]
        which notes that if we were to do all of our calculations in 
        "eye space", and were to assume that (as is normal), the eye 
        and light coordinates will not change for a rendering pass,
        (note: this limits us to directional lights!) we 
        can use a pre-calculated value which is the bisecting angle
        between the light-vector and the view-vector, called the 
        "half vector" to 
        perform approximately the same calculation.  With this value:'''
        """
            // note that in Eye coordinates, Eye_EC_dir == 0,0,-1
            H = normalize( Eye_EC_dir + Light_EC_dir )
            Spec_factor = pow( dot( H, N ), shininess )
        """
        '''Note: however, that the resulting Spec_factor is not *precisely*
        the same value as the original calculation, so the "shininess"
        exponent must be slightly lower to approximate the value that
        Phong rendering would achieve.  The value is, however, considered
        close to "real world" materials, so the Blinn method is generally 
        preferred to Phong.
        
        Traditionally, n_dot_pos would be cut off at 0.0, but that would 
        create extremely hard-edged cut-offs for specular color.  Here 
        we "fudge" the result by 0.05
        '''
        phong_weightCalc = """
        vec2 phong_weightCalc( 
            in vec3 light_pos, // light position
            in vec3 half_light, // half-way vector between light and view
            in vec3 frag_normal, // geometry normal
            in float shininess
        ) {
            // returns vec2( ambientMult, diffuseMult )
            float n_dot_pos = max( 0.0, dot( 
                frag_normal, light_pos
            ));
            float n_dot_half = 0.0;
            if (n_dot_pos > -.05) {
                n_dot_half = pow(max(0.0,dot( 
                    half_light, frag_normal
                )), shininess);
            }
            return vec2( n_dot_pos, n_dot_half);
        }		
        """
        '''We are going to use per-fragment rendering.
        As a result, our vertex shader becomes very simple, just arranging
        for the Normals to be varied across the surface.
        '''
        vertex = shaders.compileShader( 
        """
        attribute vec3 Vertex_position;
        attribute vec3 Vertex_normal;
        
        varying vec3 baseNormal;
        void main() {
            gl_Position = gl_ModelViewProjectionMatrix * vec4( 
                Vertex_position, 1.0
            );
            baseNormal = gl_NormalMatrix * normalize(Vertex_normal);
        }""", GL_VERTEX_SHADER)
        '''Our fragment shader looks much like our previous tutorial's 
        vertex shader.  As before, we have lots of uniform values,
        but now we also calculate the light's half-vector (in eye-space 
        coordinates).  The phong_weightCalc function does the core Blinn 
        calculation, and we simply use the resulting factor to add to 
        the colour value for the fragment.
        
        Note the use of the eye-coordinate-space to simplify the 
        half-vector calculation, the eye-space eye-vector is always 
        the same value (pointing down the negative Z axis), 
        and the eye-space eye-coordinate is always (0,0,0), so the 
        eye-to-vertex vector is always the eye-space vector position.
        '''
        fragment = shaders.compileShader( phong_weightCalc + """
        uniform vec4 Global_ambient;
        
        uniform vec4 Light_ambient;
        uniform vec4 Light_diffuse;
        uniform vec4 Light_specular;
        uniform vec3 Light_location;
        
        uniform float Material_shininess;
        uniform vec4 Material_specular;
        uniform vec4 Material_ambient;
        uniform vec4 Material_diffuse;
        
        varying vec3 baseNormal;
        void main() {
            // normalized eye-coordinate Light location
            vec3 EC_Light_location = normalize(
                gl_NormalMatrix * Light_location
            );
            // half-vector calculation 
            vec3 Light_half = normalize(
                EC_Light_location - vec3( 0,0,-1 )
            );
            vec2 weights = phong_weightCalc(
                EC_Light_location,
                Light_half,
                baseNormal,
                Material_shininess
            );
            
            gl_FragColor = clamp( 
            (
                (Global_ambient * Material_ambient)
                + (Light_ambient * Material_ambient)
                + (Light_diffuse * Material_diffuse * weights.x)
                // material's shininess is the only change here...
                + (Light_specular * Material_specular * weights.y)
            ), 0.0, 1.0);
        }
        """, GL_FRAGMENT_SHADER)
        
        self.shader = shaders.compileProgram(vertex,fragment)
        '''Here's the call that creates the two VBOs and the 
        count of records to render from them. If you're curious 
        you can read through the source code of the 
        OpenGLContext.scenegraph.quadrics module to read the 
        mechanism that generates the values.
        
        The sphere is a simple rendering mechanism, as for a 
        unit-sphere at the origin, the sphere's normals are the 
        same as the sphere's vertex coordinate.  The complexity 
        comes primarily in generating the triangle indices that 
        link the points generated.
        '''
        #self.coords,self.indices,self.count = Sphere( 
        #    radius = 3 
        #).compile()

        self.coords,self.indices,self.count = Sphere(radius=3).compile()

        '''We have a few more uniforms to control the specular 
        components.  Real-world coding would also calculate the 
        light's half-vector and provide it as a uniform (so that 
        it would only need to be calculated once), but we are going 
        to do the half-vector calculation in the shader to make 
        it obvious what is going on.  The legacy OpenGL pipeline 
        provides the value pre-calculated as part of the light structure 
        in GLSL.
        '''
        for uniform in (
            'Global_ambient',
            'Light_ambient','Light_diffuse','Light_location',
            'Light_specular',
            'Material_ambient','Material_diffuse',
            'Material_shininess','Material_specular',
        ):
            location = glGetUniformLocation( self.shader, uniform )
            if location in (None,-1):
                print 'Warning, no uniform: %s'%( uniform )
            setattr( self, uniform+ '_loc', location )
        for attribute in (
            'Vertex_position','Vertex_normal',
        ):
            location = glGetAttribLocation( self.shader, attribute )
            if location in (None,-1):
                print 'Warning, no attribute: %s'%( uniform )
            setattr( self, attribute+ '_loc', location )

        #Add a timer
        self.time = Timer( duration = 8.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        self.rotation =  0
        self.sensor = PhotoSensor()
        self.sensor.calibrate_ambient()
Exemple #50
0
class Cow_Animated(BaseContext):

    vertexes = None
    normals = None
    indices = None
    uv = None

    vertexbuffer = None
    normalbuffer = None
    indicesbuffer = None
    uvbuffer = None
    vertex_tweened_buffer = None

    shader = None
    texture = None
    location = None
    rotate = None

    is_trans = None
    vertex_shaders = None
    fragment_shaders = None
    texture_name = None

    def OnInit(self):

        self.is_trans = True
        self.vertex_shaders = [st.ANIMATED_VERTEX_SHADER]
        self.fragment_shaders = [st.ANIMATED_FRAGMENT_SHADER]
        self.texture_name = 'wood.jpg'
        self.time = Timer(duration=2.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.vertexes, self.indices, self.normals, self.uv = self.load_data()
        self.load_object()
        self.load_shader()
        self.load_texture()

        self.location = np.array([0.0, 0.0, 0.0])

        self.EYE = np.array([0.0, 0.0, 10.0])
        self.PREF = np.array([0.0, 0.0, -1.0])
        self.vv = np.array([0.0, 1.0, 0.0])
        self.N = (self.PREF - self.EYE) / np.linalg.norm(self.PREF - self.EYE)
        self.U = np.cross(self.N, self.vv) / np.linalg.norm(np.cross(self.N, self.vv))
        self.EYE_UP = np.cross(self.U, self.N)
        self.d = 0.1
        height = 500
        width = 500
        self.half_h = height / 2
        self.f = 100.0
        self.width = width
        self.height = height
        slope = np.sqrt((pow(self.d, 2) + pow((width / 2), 2)))
        self.fov = 2 * np.arctan(self.half_h / slope)
        left_bottom_near = self.EYE + self.d * self.N - self.half_h * self.U - self.half_h * self.EYE_UP
        right_top_near = self.EYE + self.d * self.N + self.half_h * self.U + self.half_h * self.EYE_UP
        self.VIEW = np.array([left_bottom_near[0], right_top_near[0], left_bottom_near[1], right_top_near[1],
                              np.array([self.d]), np.array([self.f])])
        self.LOOK_AT = np.array([0, 0, 0])
        self.ProjectionMatrix = glm.perspective(self.fov,
                                                float(self.width) / float(self.height), self.d, self.f)
        self.ViewMatrix = glm.lookAt(glm.vec3(self.EYE[0], self.EYE[1], self.EYE[2]),
                                     glm.vec3(self.LOOK_AT[0], self.LOOK_AT[1], self.LOOK_AT[2]),
                                     glm.vec3(self.vv[0], self.vv[1], self.vv[2])
                                     )
        self.MVP = self.ProjectionMatrix * self.ViewMatrix * glm.mat4(1.0)


    def load_data(self):
        head, vertexes, indices = ft.load_cow()
        normals = None
        if self.is_trans:
            normals = ct.cal_all_normals(vertexes, indices)
            indices = tt.polygon2triangle(indices)
        # todo:// add real uv
        uv = np.random.random((vertexes.shape[0], 2))
        return vertexes, indices, normals, uv

    def load_object(self):
        bind_type = [bt.BIND_VERTEX, bt.BIND_TWEENED_VERTEX, bt.BIND_NORMAL, bt.BIND_INDICES, bt.BIND_UV]
        self.vertexbuffer, self.normalbuffer, self.indicesbuffer, self.uvbuffer, self.vertex_tweened_buffer = bt.bind_object(
            bind_type,
            self.vertexes,
            self.indices,
            self.normals, self.uv)
        # super().load_object(bind_type)

    def load_shader(self):
        self.shader = st.Shader()
        self.shader.init_shader(self.vertex_shaders, self.fragment_shaders)
        self.shader.bind_parameters(self)

    def load_texture(self):
        self.texture = texture_t.Texture()
        self.texture.init_texture(self.texture_name)

    def Render(self, mode=0):
        BaseContext.Render(self, mode)
        self.shader.begin()
        try:
            self.set_uniform_value()
            glUniform1f(self.tween_loc, self.tween_fraction)
            glUniformMatrix4fv(self.MVP_loc, 1, GL_FALSE, glm.value_ptr(self.MVP))
            glUniformMatrix4fv(self.ModelMatrix_loc, 1, GL_FALSE, glm.value_ptr(glm.mat4(1.0)))
            glUniformMatrix4fv(self.ViewMatrix_loc, 1, GL_FALSE, glm.value_ptr(self.ViewMatrix))
            glUniform3f(self.LOCATION_OFFSET_loc, self.location[0], self.location[1], self.location[2])

            glActiveTexture(GL_TEXTURE0)
            glBindTexture(GL_TEXTURE_2D, self.texture.textureGLID)
            glUniform1i(self.diffuse_texture_loc, 0)

            glEnableVertexAttribArray(self.Vertex_position_loc)
            glBindBuffer(GL_ARRAY_BUFFER, self.vertexbuffer)
            glVertexAttribPointer(self.Vertex_position_loc, 3, GL_FLOAT, GL_FALSE, 0, None)

            glEnableVertexAttribArray(self.tweened_loc)
            glBindBuffer(GL_ARRAY_BUFFER, self.vertex_tweened_buffer)
            glVertexAttribPointer(self.tweened_loc, 3, GL_FLOAT, GL_FALSE, 0, None)

            glEnableVertexAttribArray(self.Vertex_normal_loc)
            glBindBuffer(GL_ARRAY_BUFFER, self.normalbuffer)
            glVertexAttribPointer(self.Vertex_normal_loc, 3, GL_FLOAT, GL_FALSE, 0, None)

            glEnableVertexAttribArray(self.Vertex_texture_coordinate_loc)
            glBindBuffer(GL_ARRAY_BUFFER, self.uvbuffer)
            glVertexAttribPointer(self.Vertex_texture_coordinate_loc, 2, GL_FLOAT, GL_FALSE, 0, None)

            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.indicesbuffer)

            glDrawElements(
                GL_TRIANGLES,  # draw mode
                self.indices.size,  # count of indices
                GL_UNSIGNED_SHORT,  # type of indices data
                None
            )
        finally:
            glDisableVertexAttribArray(self.Vertex_position_loc)
            glDisableVertexAttribArray(self.tweened_loc)
            glDisableVertexAttribArray(self.Vertex_normal_loc)
            glDisableVertexAttribArray(self.Vertex_texture_coordinate_loc)
            self.shader.end()

    tween_fraction = 0.0

    def OnTimerFraction(self, event):
        frac = event.fraction()
        if frac > .5:
            frac = 1.0 - frac
        frac *= 2
        self.tween_fraction = frac
        self.triggerRedraw()
        # glutPostRedisplay()

    def set_uniform_value(self):
        for uniform in self.shader.uniform_list:
            uniform_value = self.shader.uniform_default_value.get(uniform, None)
            if uniform_value is not None:
                length = len(uniform_value)
                if length == 1:
                    glUniform1f(getattr(self, uniform + '_loc'), uniform_value[0])
                elif length == 2:
                    glUniform2f(getattr(self, uniform + '_loc'), uniform_value[0], uniform_value[1])
                elif length == 3:
                    glUniform3f(getattr(self, uniform + '_loc'), uniform_value[0], uniform_value[1], uniform_value[2])
                elif length == 4:
                    glUniform4f(getattr(self, uniform + '_loc'), uniform_value[0], uniform_value[1], uniform_value[2],
                                uniform_value[3])
Exemple #51
0
    def OnInit( self ):
        """Scene set up and initial processing"""
        print """You should see a cone over a black background
    The cone should have a mapped texture (a stained-glass window)
    and should be centered on the window.
"""
        print 'press i to choose another texture for the box'
        self.addEventHandler(
            'keypress', name = 'i', function = self.OnImageSwitch
        )
        print 'press s to choose another size for the box'
        self.addEventHandler(
            'keypress', name = 's', function = self.OnSizeSwitch
        )
        self.appearance = Appearance(
            material = Material(
                diffuseColor =(1,0,0),
                specularColor = (.5,.5,.5),
            ),
            texture = ImageTexture(
                url = [images[0]]
            ),
        )
        self.cone = Shape(
            geometry = Cone( ),
            appearance = self.appearance,
        )
        self.cylinder = Shape(
            geometry = Cylinder( ),
            appearance = self.appearance,
        )
        self.box = Shape(
            geometry = Box(),
            appearance = self.appearance,
        )
        self.gear = Shape(
            geometry = Gear(),
            appearance = self.appearance,
        )
        self.teapot = Shape(
            geometry = Teapot(),
            appearance = self.appearance,
        )
        self.sphere = Shape(
            geometry = Sphere(),
            appearance = self.appearance,
        )
        self.ifs = Shape(
            geometry = IndexedFaceSet(
                coord = Coordinate(
                    point = [[-1,0,0],[1,0,0],[1,1,0],[-1,1,0]],
                ),
                coordIndex = [ 0,1,2,-1,0,2,3],
                color = Color(
                    color = [[0,0,1],[1,0,0]],
                ),
                colorIndex = [ 0,1,0,-1,0,0,1],
                solid = False,
                normalPerVertex=True,
            ),
            appearance = self.appearance,
        )
        self.sg = Transform(
            children = [
                Transform(
                    translation = (4,0,0),
                    children = [self.cone],
                ),
                Transform(
                    translation = (0,0,0),
                    children = [self.box],
                ),
                Transform(
                    translation = (-4,0,0),
                    children = [self.cylinder],
                ),
                Transform(
                    translation = (0,4,0),
                    children = [self.gear],
                    scale = (3,3,3),
                ),
                Transform(
                    translation = (0,-4,0),
                    children = [self.teapot],
                    scale = (.5,.5,.5),
                ),
                Transform(
                    translation = (4,-4,0),
                    children = [self.sphere],
                ),
                Transform(
                    translation = (-4,-4,0),
                    children = [self.ifs],
                ),
                SimpleBackground(
                    color = (.5,.5,.5),
                ),
            ],
            scale = (.75,.75,.75),
        )
        self.time = Timer( duration = 15.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
Exemple #52
0
 def OnInit( self ):
     """Initialize the context"""
     '''We've defined a uniform "tween" which represents the current 
     fractional mix between the two positions.
     
     When we were using the glVertexPointer/glColorPointer
     entry points, there were implicitly defined attribute values
     (gl_Vertex, gl_Color) that recieved our data-records.  With 
     legacy-free operation, we explicitly define the attribute values 
     which will be used.  They look very similar to the declarations
     for uniform values, save for the varying keyword.
     '''
     vertex = shaders.compileShader("""
         uniform float tween;
         attribute vec3 position;
         attribute vec3 tweened;
         attribute vec3 color;
         varying vec4 baseColor;
         void main() {
             gl_Position = gl_ModelViewProjectionMatrix * mix(
                 vec4( position,1.0),
                 vec4( tweened,1.0),
                 tween
             );
             baseColor = vec4(color,1.0);
         }""",GL_VERTEX_SHADER)
     fragment = shaders.compileShader("""
         varying vec4 baseColor;
         void main() {
             gl_FragColor = baseColor;
         }""",GL_FRAGMENT_SHADER)
     self.shader = shaders.compileProgram(vertex,fragment)
     '''Since our VBO now has two position records and one colour 
     record, we have an extra 3 floats for each vertex record.'''
     self.vbo = vbo.VBO(
         array( [
             [  0, 1, 0, 1,3,0,  0,1,0 ],
             [ -1,-1, 0, -1,-1,0,  1,1,0 ],
             [  1,-1, 0, 1,-1,0, 0,1,1 ],
             
             [  2,-1, 0, 2,-1,0, 1,0,0 ],
             [  4,-1, 0, 4,-1,0, 0,1,0 ],
             [  4, 1, 0, 4,9,0, 0,0,1 ],
             [  2,-1, 0, 2,-1,0, 1,0,0 ],
             [  4, 1, 0, 1,3,0, 0,0,1 ],
             [  2, 1, 0, 1,-1,0, 0,1,1 ],
         ],'f')
     )
     '''As with uniforms, we must use opaque "location" values 
     to refer to our attributes when calling into the GL.'''
     self.position_location = glGetAttribLocation( 
         self.shader, 'position' 
     )
     self.tweened_location = glGetAttribLocation(
         self.shader, 'tweened',
     )
     self.color_location = glGetAttribLocation( 
         self.shader, 'color' 
     )
     self.tween_location = glGetUniformLocation(
         self.shader, 'tween',
     )
     '''The OpenGLContext timer class is setup here to provide 
     a 0.0 -> 1.0 animation event and pass it to the given function.'''
     self.time = Timer( duration = 2.0, repeating = 1 )
     self.time.addEventHandler( "fraction", self.OnTimerFraction )
     self.time.register (self)
     self.time.start ()
Exemple #53
0
class TestContext( BaseContext ):
    rotation = 0.00
    rotation_2 = 0.00
    light_location = (0,10,5)
    def Render( self, mode = 0):
        BaseContext.Render( self, mode )
        glRotate( self.rotation, 0,1,0 )
        glRotate( self.rotation_2, 1,0,1 )
        glUseProgram(self.program)
        glUniform3fv( self.light_uniform_loc, 1, self.light_location )
        glutSolidSphere(1.0,32,32)
        glTranslate( 1,0,2 )
        glutSolidCube( 1.0 )
        glTranslate( 2,0,0 )
        glFrontFace(GL_CW)
        try:
            glutSolidTeapot( 1.0)
        finally:
            glFrontFace(GL_CCW)
    def OnInit( self ):
        """Scene set up and initial processing"""
        self.program = shaders.compileProgram(
            shaders.compileShader(
                '''
                varying vec3 normal;
                void main() {
                    normal = gl_NormalMatrix * gl_Normal;
                    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                }
                ''',
                GL_VERTEX_SHADER,
            ),
            shaders.compileShader(
                '''
                uniform vec3 light_location;
                varying vec3 normal;
                void main() {
                    float intensity;
                    vec4 color;
                    vec3 n = normalize(normal);
                    vec3 l = normalize(light_location).xyz;
                
                    // quantize to 5 steps (0, .25, .5, .75 and 1)
                    intensity = (floor(dot(l, n) * 4.0) + 1.0)/4.0;
                    color = vec4(intensity*1.0, intensity*0.5, intensity*0.5,
                        intensity*1.0);
                
                    gl_FragColor = color;
                }
                ''',
                GL_FRAGMENT_SHADER,
            ),
        )
        self.light_uniform_loc = glGetUniformLocation( self.program, 'light_location' )
        self.time = Timer( duration = 2.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
    def OnTimerFraction( self, event ):
        self.rotation = event.fraction() * 360
        self.rotation_2 = -event.fraction() * 360
class TestContext( BaseContext ):
    """Particle testing code context object"""
    initialPosition = (0,7,20)
    lastFraction = 0.0
    def OnInit( self ):
        """Do all of our setup functions..."""
        BaseContext.OnInit( self )
        print """You should see something that looks vaguely like
a water-fountain, with individual droplets starting
blue and turning white."""
        '''The PointSet node will do the actual work of rendering 
        our points into the GL.  We start it off with all points 
        at the emitter location and with initial colour.'''
        self.points = PointSet(
            coord = Coordinate(
                point = [emitter]*count
            ),
            color = Color(
                color = [initialColor]*count
            ),
            minSize = 7.0,
            maxSize = 10.0,
            attenuation = [0,1,0],
        )
        '''We use a simple Appearance node to apply a texture to the 
        PointSet, the PointSet will use this to enable sprite-based 
        rendering if the extension(s) are available.'''
        self.shape = Shape(
            appearance = Appearance(
                texture = ImageTexture( url='_particle.png' ),
            ),
            geometry = self.points,
        )
        self.text = Text(
            string = ["""Current multiplier: 1.0"""],
            fontStyle = FontStyle(
                family='SANS', format = 'bitmap',
                justify = 'MIDDLE',
            ),
        )
        self.sg = sceneGraph( children = [
            self.shape,
            SimpleBackground( color = (.5,.5,.5),),
            Transform(
                translation = (0,-1,0),
                children = [
                    Shape(
                        geometry = self.text
                    ),
                ],
            ),
        ] )
        self.velocities = array([ (0,0,0)]*count, 'd')
        self.colorVelocities = array( colorVelocities, 'd')
        print '  <s> make time pass more slowly'
        print '  <f> make time pass faster'
        print '  <h> higher'
        print '  <l> (L) lower'
        print '  <[> smaller drops'
        print '  <]> larger drops'
        self.addEventHandler( "keypress", name="s", function = self.OnSlower)
        self.addEventHandler( "keypress", name="f", function = self.OnFaster)
        self.addEventHandler( "keypress", name="h", function = self.OnHigher)
        self.addEventHandler( "keypress", name="l", function = self.OnLower)
        self.addEventHandler( "keypress", name="]", function = self.OnLarger)
        self.addEventHandler( "keypress", name="[", function = self.OnSmaller)
        '''First timer will provide the general simulation heartbeat.'''
        self.time = Timer( duration = 1.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
        '''Second timer provides a cycle on which the fountain 
        reduces/increases the speed at which droplets are started.'''
        self.time2 = Timer( duration = 5.0, repeating = 1 )
        self.time2.addEventHandler( "cycle", self.OnLower )
        self.time2.register (self)
        self.time2.start ()

    ### Timer callback
    def OnTimerFraction( self, event ):
        """Perform the particle-system simulation calculations"""
        points = self.points.coord.point
        colors = self.points.color.color
        '''Our calculations are going to need to know how much time 
        has passed since our last event.  This is complicated by the 
        fact that a "fraction" event is cyclic, returning to 0.0 after 
        1.0.'''
        f = event.fraction()
        if f < self.lastFraction:
            f += 1.0
        deltaFraction = (f-self.lastFraction)
        self.lastFraction = event.fraction()
        '''If we have received an event which is so soon after a 
        previous event as to have a 0.0s delta (this does happen 
        on some platforms), then we need to ignore this simulation 
        tick.'''
        if not deltaFraction:
            return
        '''Each droplet has been moving at their current velocity 
        for deltaFraction seconds, update their position with the 
        results of this speed * time.  You'll note that this is not 
        precisely accurate for a body under acceleration, but it 
        makes for easy calculations.  Two machines running 
        the same simulation will get *different* results here, as 
        a faster machine will apply acceleration more frequently,
        resulting in a faster total velocity.'''
        points = points + (self.velocities*deltaFraction)
        '''We also cycle the droplet's colour value, though with 
        the applied texture it's somewhat hard to see.'''
        colors = colors + (self.colorVelocities*deltaFraction)
        '''Now, apply acceleration to the current velocities such 
        that the droplets have a new velocity for the next simulation 
        tick.'''
        self.velocities[:,1] = self.velocities[:,1] + (gravity * deltaFraction)
        '''Find all droplets which have "retired" by falling below the 
        y==0.0 plane.'''
        below = less_equal( points[:,1], 0.0)
        dead = nonzero(below)
        if isinstance( dead, tuple ):
            # weird numpy change here...
            dead = dead[0]
        if len(dead):
            '''Move all dead droplets back to the emitter.'''
            def put( a, ind, b ):
                for i in ind:
                    a[i] = b
            put( points, dead, emitter)
            '''Re-spawn up to half of the droplets...'''
            dead = dead[:(len(dead)//2)+1]
            if len(dead):
                '''Reset color to initialColor, as we are sending out 
                these droplets right now.'''
                put( colors, dead, initialColor)
                '''Assign slightly randomized versions of our initial 
                velocity for each of the re-spawned droplets.  Replace 
                the current velocities with the new velocities.'''
                if RandomArray:
                    velocities = (RandomArray.random( (len(dead),3) ) + [-.5, 0.0, -.5 ]) * initialVelocityVector
                else:
                    velocities = [
                        array( (random.random()-.5, random.random(), random.random()-.5), 'f')* initialVelocityVector
                        for x in xrange(len(dead))
                    ]
                def copy( a, ind, b ):
                    for x in xrange(len(ind)):
                        i = ind[x]
                        a[i] = b[x]
                copy( self.velocities, dead, velocities)
        '''Now re-set the point/color fields so that the nodes notice 
        the array has changed and they update the GL with the changed 
        values.'''
        self.points.coord.point = points
        self.points.color.color = colors
        
    '''Set up keyboard callbacks'''
    def OnSlower( self, event ):
        self.time.internal.multiplier = self.time.internal.multiplier /2.0
        if glutfont:
            self.text.string = [ "Current multiplier: %s"%( self.time.internal.multiplier,)]
        else:
            print "slower",self.time.internal.multiplier
    def OnFaster( self, event ):
        self.time.internal.multiplier = self.time.internal.multiplier * 2.0
        if glutfont:
            self.text.string = [ "Current multiplier: %s"%( self.time.internal.multiplier,)]
        else:
            print "faster",self.time.internal.multiplier
    def OnHigher( self, event ):
        global initialVelocityVector
        initialVelocityVector *= [1,1.25,1]
    def OnLower( self, event ):
        global initialVelocityVector
        if hasattr(event,'count') and not event.count() % 4:
            initialVelocityVector[:] = [1.5,20,1.5]
        else:
            initialVelocityVector /= [1,1.5,1]
    def OnLarger( self, event ):
        self.points.minSize += 1.0
        self.points.maxSize += 1.0
    def OnSmaller( self, event ):
        self.points.minSize = max((0.0,self.points.minSize-1.0))
        self.points.maxSize = max((1.0,self.points.maxSize-1.0))
class TestContext(BaseContext):
    """Demonstrates use of attribute types in GLSL
    """
    def OnInit(self):
        """Initialize the context"""
        '''== Phong and Blinn Reflectance ==

        A shiny surface will tend to have a "bright spot" at the point 
        on the surface where the angle of incidence for the reflected
        light ray and the viewer's ray are (close to) equal.  
        A perfect mirror would have the brights spot solely when the 
        two vectors are exactly equal, while a perfect Lambertian
        surface would have the "bright spot" spread across the entire
        surface.
        
        The Phong rendering process models this as a setting, traditionally
        called material "shininess" in Legacy OpenGL.  This setting acts 
        as a power which raises the cosine (dot product) of the 
        angle between the reflected ray and the eye.  The calculation of 
        the cosine (dot product) of the two angles requires that we do 
        a dot product of the two angles once for each vertex/fragment 
        for which we wish to calculate the specular reflectance, we also 
        have to find the angle of reflectance before we can do the 
        calculation:'''
        """
            L_dir = (V_pos-L_pos)
            R = 2N*(dot( N, L_dir))-L_dir
            // Note: in eye-coordinate system, Eye_pos == (0,0,0)
            Spec_factor = pow( dot( R, V_pos-Eye_pos ), shininess)
        """
        '''which, as we can see, involves the vertex position in a number 
        of stages of the operation, so requires recalculation all through 
        the rendering operation.
        
        There is, however, a simplified version of Phong Lighting called 
        [http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model Blinn-Phong]
        which notes that if we were to do all of our calculations in 
        "eye space", and were to assume that (as is normal), the eye 
        and light coordinates will not change for a rendering pass,
        (note: this limits us to directional lights!) we 
        can use a pre-calculated value which is the bisecting angle
        between the light-vector and the view-vector, called the 
        "half vector" to 
        perform approximately the same calculation.  With this value:'''
        """
            // note that in Eye coordinates, Eye_EC_dir == 0,0,-1
            H = normalize( Eye_EC_dir + Light_EC_dir )
            Spec_factor = pow( dot( H, N ), shininess )
        """
        '''Note: however, that the resulting Spec_factor is not *precisely*
        the same value as the original calculation, so the "shininess"
        exponent must be slightly lower to approximate the value that
        Phong rendering would achieve.  The value is, however, considered
        close to "real world" materials, so the Blinn method is generally 
        preferred to Phong.
        
        Traditionally, n_dot_pos would be cut off at 0.0, but that would 
        create extremely hard-edged cut-offs for specular color.  Here 
        we "fudge" the result by 0.05
        '''
        phong_weightCalc = """
        vec2 phong_weightCalc( 
            in vec3 light_pos, // light position
            in vec3 half_light, // half-way vector between light and view
            in vec3 frag_normal, // geometry normal
            in float shininess
        ) {
            // returns vec2( ambientMult, diffuseMult )
            float n_dot_pos = max( 0.0, dot( 
                frag_normal, light_pos
            ));
            float n_dot_half = 0.0;
            if (n_dot_pos > -.05) {
                n_dot_half = pow(max(0.0,dot( 
                    half_light, frag_normal
                )), shininess);
            }
            return vec2( n_dot_pos, n_dot_half);
        }		
        """
        '''We are going to use per-fragment rendering.
        As a result, our vertex shader becomes very simple, just arranging
        for the Normals to be varied across the surface.
        '''
        vertex = shaders.compileShader(
            """
        attribute vec3 Vertex_position;
        attribute vec3 Vertex_normal;
        
        varying vec3 baseNormal;
        void main() {
            gl_Position = gl_ModelViewProjectionMatrix * vec4( 
                Vertex_position, 1.0
            );
            baseNormal = gl_NormalMatrix * normalize(Vertex_normal);
        }""", GL_VERTEX_SHADER)
        '''Our fragment shader looks much like our previous tutorial's 
        vertex shader.  As before, we have lots of uniform values,
        but now we also calculate the light's half-vector (in eye-space 
        coordinates).  The phong_weightCalc function does the core Blinn 
        calculation, and we simply use the resulting factor to add to 
        the colour value for the fragment.
        
        Note the use of the eye-coordinate-space to simplify the 
        half-vector calculation, the eye-space eye-vector is always 
        the same value (pointing down the negative Z axis), 
        and the eye-space eye-coordinate is always (0,0,0), so the 
        eye-to-vertex vector is always the eye-space vector position.
        '''
        fragment = shaders.compileShader(
            phong_weightCalc + """
        uniform vec4 Global_ambient;
        
        uniform vec4 Light_ambient;
        uniform vec4 Light_diffuse;
        uniform vec4 Light_specular;
        uniform vec3 Light_location;
        
        uniform float Material_shininess;
        uniform vec4 Material_specular;
        uniform vec4 Material_ambient;
        uniform vec4 Material_diffuse;
        
        varying vec3 baseNormal;
        void main() {
            // normalized eye-coordinate Light location
            vec3 EC_Light_location = normalize(
                gl_NormalMatrix * Light_location
            );
            // half-vector calculation 
            vec3 Light_half = normalize(
                EC_Light_location - vec3( 0,0,-1 )
            );
            vec2 weights = phong_weightCalc(
                EC_Light_location,
                Light_half,
                baseNormal,
                Material_shininess
            );
            
            gl_FragColor = clamp( 
            (
                (Global_ambient * Material_ambient)
                + (Light_ambient * Material_ambient)
                + (Light_diffuse * Material_diffuse * weights.x)
                // material's shininess is the only change here...
                + (Light_specular * Material_specular * weights.y)
            ), 0.0, 1.0);
        }
        """, GL_FRAGMENT_SHADER)

        self.shader = shaders.compileProgram(vertex, fragment)
        '''Here's the call that creates the two VBOs and the 
        count of records to render from them. If you're curious 
        you can read through the source code of the 
        OpenGLContext.scenegraph.quadrics module to read the 
        mechanism that generates the values.
        
        The sphere is a simple rendering mechanism, as for a 
        unit-sphere at the origin, the sphere's normals are the 
        same as the sphere's vertex coordinate.  The complexity 
        comes primarily in generating the triangle indices that 
        link the points generated.
        '''
        #self.coords,self.indices,self.count = Sphere(
        #    radius = 3
        #).compile()

        self.coords, self.indices, self.count = Sphere(radius=3).compile()
        '''We have a few more uniforms to control the specular 
        components.  Real-world coding would also calculate the 
        light's half-vector and provide it as a uniform (so that 
        it would only need to be calculated once), but we are going 
        to do the half-vector calculation in the shader to make 
        it obvious what is going on.  The legacy OpenGL pipeline 
        provides the value pre-calculated as part of the light structure 
        in GLSL.
        '''
        for uniform in (
                'Global_ambient',
                'Light_ambient',
                'Light_diffuse',
                'Light_location',
                'Light_specular',
                'Material_ambient',
                'Material_diffuse',
                'Material_shininess',
                'Material_specular',
        ):
            location = glGetUniformLocation(self.shader, uniform)
            if location in (None, -1):
                print 'Warning, no uniform: %s' % (uniform)
            setattr(self, uniform + '_loc', location)
        for attribute in (
                'Vertex_position',
                'Vertex_normal',
        ):
            location = glGetAttribLocation(self.shader, attribute)
            if location in (None, -1):
                print 'Warning, no attribute: %s' % (uniform)
            setattr(self, attribute + '_loc', location)

        #Add a timer
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.rotation = 0
        self.sensor = PhotoSensor()
        self.sensor.calibrate_ambient()

    def OnTimerFraction(self, event):
        r = self.sensor.getSensorReading()
        angle = self.sensor.getAngle(r)
        self.rotation = angle / 180.0 * pi

    def getLightLocation(self):
        # read from serial port
        return [math.cos(self.rotation), math.sin(self.rotation), 0] * 5

    def Render(self, mode=None):
        """Render the geometry for the scene."""
        BaseContext.Render(self, mode)
        glUseProgram(self.shader)
        try:
            '''==Indexed VBO Rendering==
            
            You'll notice here that we are binding two different VBO 
            objects.  As we mentioned above, the Sphere renderer 
            generated both VBOs, but doesn't the second binding replace 
            the first binding?  That is, why doesn't OpenGL try to read 
            the Vertex data out of the indices VBO?
            
            OpenGL defines multiple binding "targets" for VBOs, the 
            first VBO (vertices) was bound to the GL_ARRAY_BUFFER
            target (the default for the class), which is used for reading 
            per-vertex data arrays, while the indices buffer was defined
            as targetting the GL_ELEMENT_ARRAY_BUFFER, which is used
            solely for reading indices.
            
            Each target can be bound to a different VBO, and thus we can
            bind both VBOs at the same time without confusion.
            '''
            self.coords.bind()
            self.indices.bind()
            '''Here, being lazy, we use the numpy array's nbytes value 
            to specify the stride between records.  The VBO object has 
            a "data" value which is the data-set which was initially 
            passed to the VBO constructor.  The first element in this 
            array is a single vertex record.  This array happens to have 
            8 floating-point values (24 bytes), the first three being 
            the vertex position, the next two being the texture coordinate 
            and the last three being the vertex normal.  We'll ignore 
            the texture coordinate for now.
            '''
            stride = self.coords.data[0].nbytes
            try:
                glUniform4f(self.Global_ambient_loc, .05, .05, .05, .1)
                glUniform4f(self.Light_ambient_loc, .1, .1, .1, 1.0)
                glUniform4f(self.Light_diffuse_loc, .25, .25, .25, 1)
                '''We set up a yellow-ish specular component in the 
                light and move it to rest "just over our right shoulder"
                in relation to the initial camera.'''
                glUniform4f(self.Light_specular_loc, 0.0, 1.0, 0, 1)

                lloc = self.getLightLocation()
                glUniform3f(self.Light_location_loc, lloc[0], lloc[1], lloc[2])

                glUniform4f(self.Material_ambient_loc, .1, .1, .1, 1.0)
                glUniform4f(self.Material_diffuse_loc, .15, .15, .15, 1)
                '''We make the material have a bright specular white 
                colour and an extremely "shiny" surface.  The shininess 
                value has the effect of reducing the area of the
                highlight, as the cos of the angle is raised 
                to the power of the (fractional) shininess.'''
                glUniform4f(self.Material_specular_loc, 1.0, 1.0, 1.0, 1.0)
                glUniform1f(self.Material_shininess_loc, .95)
                glEnableVertexAttribArray(self.Vertex_position_loc)
                glEnableVertexAttribArray(self.Vertex_normal_loc)
                glVertexAttribPointer(self.Vertex_position_loc, 3, GL_FLOAT,
                                      False, stride, self.coords)
                glVertexAttribPointer(self.Vertex_normal_loc, 3, GL_FLOAT,
                                      False, stride, self.coords + (5 * 4))
                '''Here we introduce the OpenGL call which renders via 
                an index-array rather than just rendering vertices in 
                definition order.  The last two arguments tell OpenGL 
                what data-type we've used for the indices (the Sphere 
                renderer uses shorts).  The indices VBO is actually 
                just passing the value c_void_p( 0 ) (i.e. a null pointer),
                which causes OpenGL to use the currently bound VBO for 
                the GL_ELEMENT_ARRAY_BUFFER target.
                '''
                glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_SHORT,
                               self.indices)
            finally:
                '''Note the need to unbind *both* VBOs, we have to free 
                *both* VBO targets to avoid any other rendering operation 
                from trying to access the VBOs.'''
                self.coords.unbind()
                self.indices.unbind()
                glDisableVertexAttribArray(self.Vertex_position_loc)
                glDisableVertexAttribArray(self.Vertex_normal_loc)
        finally:
            glUseProgram(0)
Exemple #56
0
class TestContext( BaseContext ):
    currentImage = 0
    currentSize = 0
    def OnInit( self ):
        """Scene set up and initial processing"""
        print """You should see a cone over a black background
    The cone should have a mapped texture (a stained-glass window)
    and should be centered on the window.
"""
        print 'press i to choose another texture for the box'
        self.addEventHandler(
            'keypress', name = 'i', function = self.OnImageSwitch
        )
        print 'press s to choose another size for the box'
        self.addEventHandler(
            'keypress', name = 's', function = self.OnSizeSwitch
        )
        self.appearance = Appearance(
            material = Material(
                diffuseColor =(1,0,0),
                specularColor = (.5,.5,.5),
            ),
            texture = ImageTexture(
                url = [images[0]]
            ),
        )
        self.cone = Shape(
            geometry = Cone( ),
            appearance = self.appearance,
        )
        self.cylinder = Shape(
            geometry = Cylinder( ),
            appearance = self.appearance,
        )
        self.box = Shape(
            geometry = Box(),
            appearance = self.appearance,
        )
        self.gear = Shape(
            geometry = Gear(),
            appearance = self.appearance,
        )
        self.teapot = Shape(
            geometry = Teapot(),
            appearance = self.appearance,
        )
        self.sphere = Shape(
            geometry = Sphere(),
            appearance = self.appearance,
        )
        self.ifs = Shape(
            geometry = IndexedFaceSet(
                coord = Coordinate(
                    point = [[-1,0,0],[1,0,0],[1,1,0],[-1,1,0]],
                ),
                coordIndex = [ 0,1,2,-1,0,2,3],
                color = Color(
                    color = [[0,0,1],[1,0,0]],
                ),
                colorIndex = [ 0,1,0,-1,0,0,1],
                solid = False,
                normalPerVertex=True,
            ),
            appearance = self.appearance,
        )
        self.sg = Transform(
            children = [
                Transform(
                    translation = (4,0,0),
                    children = [self.cone],
                ),
                Transform(
                    translation = (0,0,0),
                    children = [self.box],
                ),
                Transform(
                    translation = (-4,0,0),
                    children = [self.cylinder],
                ),
                Transform(
                    translation = (0,4,0),
                    children = [self.gear],
                    scale = (3,3,3),
                ),
                Transform(
                    translation = (0,-4,0),
                    children = [self.teapot],
                    scale = (.5,.5,.5),
                ),
                Transform(
                    translation = (4,-4,0),
                    children = [self.sphere],
                ),
                Transform(
                    translation = (-4,-4,0),
                    children = [self.ifs],
                ),
                SimpleBackground(
                    color = (.5,.5,.5),
                ),
            ],
            scale = (.75,.75,.75),
        )
        self.time = Timer( duration = 15.0, repeating = 1 )
        self.time.addEventHandler( "fraction", self.OnTimerFraction )
        self.time.register (self)
        self.time.start ()
    def OnTimerFraction( self, event ):
        self.sg.rotation = array([0,1,0,event.fraction()*pi*2],'f')
        self.appearance.material.diffuseColor = [event.fraction()]*3
        self.triggerRedraw( False )
    def OnImageSwitch( self, event=None ):
        """Choose a new mapped texture"""
        self.currentImage = currentImage = self.currentImage+1
        newImage = images[currentImage%len(images)]
        self.appearance.texture.url = [ newImage ]
        print "new image (loading) ->", newImage
    def OnSizeSwitch( self, event=None ):
        """Choose a new size"""
        self.currentSize = currentSize = self.currentSize+1
        newSize = cone_sizes[currentSize%len(cone_sizes)]
        self.cone.geometry.bottomRadius = newSize
        newSize = cone_sizes[(currentSize+1)%len(cone_sizes)]
        self.cone.geometry.height = newSize
        
        self.box.geometry.size = (newSize,newSize,newSize)
        self.cylinder.geometry.height = newSize
        self.cylinder.geometry.radius = newSize * .25
        self.gear.geometry.outer_radius = newSize * .25
        self.teapot.geometry.size = newSize
        self.sphere.geometry.radius = newSize
        print "new size ->", newSize
        self.triggerRedraw(True)
    def OnInit(self):
        """Initialize the context"""
        '''== Phong and Blinn Reflectance ==

        A shiny surface will tend to have a "bright spot" at the point 
        on the surface where the angle of incidence for the reflected
        light ray and the viewer's ray are (close to) equal.  
        A perfect mirror would have the brights spot solely when the 
        two vectors are exactly equal, while a perfect Lambertian
        surface would have the "bright spot" spread across the entire
        surface.
        
        The Phong rendering process models this as a setting, traditionally
        called material "shininess" in Legacy OpenGL.  This setting acts 
        as a power which raises the cosine (dot product) of the 
        angle between the reflected ray and the eye.  The calculation of 
        the cosine (dot product) of the two angles requires that we do 
        a dot product of the two angles once for each vertex/fragment 
        for which we wish to calculate the specular reflectance, we also 
        have to find the angle of reflectance before we can do the 
        calculation:'''
        """
            L_dir = (V_pos-L_pos)
            R = 2N*(dot( N, L_dir))-L_dir
            // Note: in eye-coordinate system, Eye_pos == (0,0,0)
            Spec_factor = pow( dot( R, V_pos-Eye_pos ), shininess)
        """
        '''which, as we can see, involves the vertex position in a number 
        of stages of the operation, so requires recalculation all through 
        the rendering operation.
        
        There is, however, a simplified version of Phong Lighting called 
        [http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model Blinn-Phong]
        which notes that if we were to do all of our calculations in 
        "eye space", and were to assume that (as is normal), the eye 
        and light coordinates will not change for a rendering pass,
        (note: this limits us to directional lights!) we 
        can use a pre-calculated value which is the bisecting angle
        between the light-vector and the view-vector, called the 
        "half vector" to 
        perform approximately the same calculation.  With this value:'''
        """
            // note that in Eye coordinates, Eye_EC_dir == 0,0,-1
            H = normalize( Eye_EC_dir + Light_EC_dir )
            Spec_factor = pow( dot( H, N ), shininess )
        """
        '''Note: however, that the resulting Spec_factor is not *precisely*
        the same value as the original calculation, so the "shininess"
        exponent must be slightly lower to approximate the value that
        Phong rendering would achieve.  The value is, however, considered
        close to "real world" materials, so the Blinn method is generally 
        preferred to Phong.
        
        Traditionally, n_dot_pos would be cut off at 0.0, but that would 
        create extremely hard-edged cut-offs for specular color.  Here 
        we "fudge" the result by 0.05
        '''
        phong_weightCalc = """
        vec2 phong_weightCalc( 
            in vec3 light_pos, // light position
            in vec3 half_light, // half-way vector between light and view
            in vec3 frag_normal, // geometry normal
            in float shininess
        ) {
            // returns vec2( ambientMult, diffuseMult )
            float n_dot_pos = max( 0.0, dot( 
                frag_normal, light_pos
            ));
            float n_dot_half = 0.0;
            if (n_dot_pos > -.05) {
                n_dot_half = pow(max(0.0,dot( 
                    half_light, frag_normal
                )), shininess);
            }
            return vec2( n_dot_pos, n_dot_half);
        }		
        """
        '''We are going to use per-fragment rendering.
        As a result, our vertex shader becomes very simple, just arranging
        for the Normals to be varied across the surface.
        '''
        vertex = shaders.compileShader(
            """
        attribute vec3 Vertex_position;
        attribute vec3 Vertex_normal;
        
        varying vec3 baseNormal;
        void main() {
            gl_Position = gl_ModelViewProjectionMatrix * vec4( 
                Vertex_position, 1.0
            );
            baseNormal = gl_NormalMatrix * normalize(Vertex_normal);
        }""", GL_VERTEX_SHADER)
        '''Our fragment shader looks much like our previous tutorial's 
        vertex shader.  As before, we have lots of uniform values,
        but now we also calculate the light's half-vector (in eye-space 
        coordinates).  The phong_weightCalc function does the core Blinn 
        calculation, and we simply use the resulting factor to add to 
        the colour value for the fragment.
        
        Note the use of the eye-coordinate-space to simplify the 
        half-vector calculation, the eye-space eye-vector is always 
        the same value (pointing down the negative Z axis), 
        and the eye-space eye-coordinate is always (0,0,0), so the 
        eye-to-vertex vector is always the eye-space vector position.
        '''
        fragment = shaders.compileShader(
            phong_weightCalc + """
        uniform vec4 Global_ambient;
        
        uniform vec4 Light_ambient;
        uniform vec4 Light_diffuse;
        uniform vec4 Light_specular;
        uniform vec3 Light_location;
        
        uniform float Material_shininess;
        uniform vec4 Material_specular;
        uniform vec4 Material_ambient;
        uniform vec4 Material_diffuse;
        
        varying vec3 baseNormal;
        void main() {
            // normalized eye-coordinate Light location
            vec3 EC_Light_location = normalize(
                gl_NormalMatrix * Light_location
            );
            // half-vector calculation 
            vec3 Light_half = normalize(
                EC_Light_location - vec3( 0,0,-1 )
            );
            vec2 weights = phong_weightCalc(
                EC_Light_location,
                Light_half,
                baseNormal,
                Material_shininess
            );
            
            gl_FragColor = clamp( 
            (
                (Global_ambient * Material_ambient)
                + (Light_ambient * Material_ambient)
                + (Light_diffuse * Material_diffuse * weights.x)
                // material's shininess is the only change here...
                + (Light_specular * Material_specular * weights.y)
            ), 0.0, 1.0);
        }
        """, GL_FRAGMENT_SHADER)

        self.shader = shaders.compileProgram(vertex, fragment)
        '''Here's the call that creates the two VBOs and the 
        count of records to render from them. If you're curious 
        you can read through the source code of the 
        OpenGLContext.scenegraph.quadrics module to read the 
        mechanism that generates the values.
        
        The sphere is a simple rendering mechanism, as for a 
        unit-sphere at the origin, the sphere's normals are the 
        same as the sphere's vertex coordinate.  The complexity 
        comes primarily in generating the triangle indices that 
        link the points generated.
        '''
        #self.coords,self.indices,self.count = Sphere(
        #    radius = 3
        #).compile()

        self.coords, self.indices, self.count = Sphere(radius=3).compile()
        '''We have a few more uniforms to control the specular 
        components.  Real-world coding would also calculate the 
        light's half-vector and provide it as a uniform (so that 
        it would only need to be calculated once), but we are going 
        to do the half-vector calculation in the shader to make 
        it obvious what is going on.  The legacy OpenGL pipeline 
        provides the value pre-calculated as part of the light structure 
        in GLSL.
        '''
        for uniform in (
                'Global_ambient',
                'Light_ambient',
                'Light_diffuse',
                'Light_location',
                'Light_specular',
                'Material_ambient',
                'Material_diffuse',
                'Material_shininess',
                'Material_specular',
        ):
            location = glGetUniformLocation(self.shader, uniform)
            if location in (None, -1):
                print 'Warning, no uniform: %s' % (uniform)
            setattr(self, uniform + '_loc', location)
        for attribute in (
                'Vertex_position',
                'Vertex_normal',
        ):
            location = glGetAttribLocation(self.shader, attribute)
            if location in (None, -1):
                print 'Warning, no attribute: %s' % (uniform)
            setattr(self, attribute + '_loc', location)

        #Add a timer
        self.time = Timer(duration=8.0, repeating=1)
        self.time.addEventHandler("fraction", self.OnTimerFraction)
        self.time.register(self)
        self.time.start()
        self.rotation = 0
        self.sensor = PhotoSensor()
        self.sensor.calibrate_ambient()