def __init__(self, shader="post_base", mipmap=False, add_tex=None, scale=1.0, camera=None, divide=1): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *add_tex* list of textures. If additional textures can be used by the shader then they can be added here. *scale* will only render this proportion of the full screen which will then be mapped to the full uv of the Sprite. The camera object passed (below) will need to have the same scale set to avoid perspective distortion *camera* the camera to use for rendering to the offscreen texture *divide* allow the sprite to be created with intermediate vertices to allow interesting vertex shader effects """ super(PostProcess, self).__init__("postprocess") self.scale = scale # load shader self.shader = Shader(shader) if camera is None: self.viewcam = Camera.instance( ) # in case this is prior to one being created else: self.viewcam = camera self.camera = Camera(is_3d=False) self.sprite = LodSprite(z=20.0, w=self.ix, h=self.iy, n=divide) self.sprite.set_2d_size(w=self.ix, h=self.iy) for b in self.sprite.buf: b.unib[6] = self.scale # ufact b.unib[7] = self.scale # vfact b.unib[9] = (1.0 - self.scale) * 0.5 # uoffset b.unib[10] = (1.0 - self.scale) * 0.5 # voffset self.blend = True self.mipmap = mipmap self.tex_list = [ self ] # TODO check if this self reference causes graphics memory leaks if add_tex: self.tex_list.extend(add_tex)
def __init__(self, position, light, scale=10.0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") self.LIGHT_CAM = Camera(is_3d=False, scale=scale) l_p = light.lightpos l_len = (l_p[0]**2 + l_p[1]**2 + l_p[2]**2)**0.5 self.OFFSET = [200.0 * i / l_len for i in l_p] self.LIGHT_CAM.position( [position[i] - o for i, o in enumerate(self.OFFSET)]) self.tilt, self.rot = self.LIGHT_CAM.point_at(position) self.cast_shader = Shader("shadowcast")
def __init__(self, emap, light): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") # load shader for casting shadows and camera self.cshader = Shader("uv_flat") self.mshader = Shader("mat_flat") # keep copy of ElevationMap self.emap = emap self.emap.set_material((0.0, 0.0, 0.0)) # hide bits below ground #TODO doesn't cope with z light positions self.eye = [-500.0 * i for i in light.lightpos] # good distance away if self.eye[1] <= 0: # must have +ve y self.eye[1] = 500.0 if abs(self.eye[0]) > abs(self.eye[2]): #x val is bigger than z val #change scale so map just fits on screen if self.eye[0] < 0: su, sv = 1.0, 1.0 else: su, sv = -1.0, -1.0 self.scaleu = float(self.iy) / self.emap.width self.scalev = float(self.ix)/ self.emap.depth self.eye[2] = 0 self.scaleu = self.scaleu / self.eye[1] * (self.eye[0]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 1.0 #orientation flag self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[0] / self.eye[1] #height adjustment else: #change scale so map just fits on screen if self.eye[2] < 0: su, sv = 1.0, -1.0 else: su, sv = -1.0, 1.0 self.scaleu = float(self.iy) / self.emap.depth self.scalev = float(self.ix)/ self.emap.width self.eye[0] = 0 self.scaleu = self.scaleu / self.eye[1] * (self.eye[2]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 0.0 self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[2] / self.eye[1] if abs(self.scaleu) > abs(self.scalev): self.scale = 3.0 * self.scalev # multiplication factor to reduce pixeliness else: self.scale = 3.0 * self.scaleu self.scaleu = su * self.scale / self.scaleu # reused later in end_cast self.scalev = sv * self.scale / self.scalev self.camera0 = Camera() # default instance created as normal, just in case! self.camera = Camera(is_3d=False, eye=self.eye, scale=self.scale) # load shader for drawing map with shadows self.dshader = Shader("shadowcast")
def _loop_begin(self): # TODO(rec): check if the window was resized and resize it, removing # code from MegaStation to here. if not ON_PI: n = xlib.XEventsQueued(self.opengl.d, xlib.QueuedAfterFlush) for i in range(n): if xlib.XCheckMaskEvent(self.opengl.d, KeyPressMask, self.ev): self.event_list.append(self.ev) else: xlib.XNextEvent(self.opengl.d, self.ev) if self.ev.type == ClientMessage: if (self.ev.xclient.data.l[0] == self.opengl.WM_DELETE_WINDOW.value): self.destroy() self.clear() with self.lock: self.sprites_to_load, to_load = set(), self.sprites_to_load self.sprites.extend(to_load) self._for_each_sprite(lambda s: s.load_opengl(), to_load) if MARK_CAMERA_CLEAN_ON_EACH_LOOP: from pi3d.Camera import Camera camera = Camera.instance() if camera: camera.was_moved = False if self.tidy_needed: self._tidy()
def __init__(self, shader="post_base", mipmap=False, add_tex=None, divide=1): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *add_tex* list of textures. If additional textures can be used by the shader then they can be added here. """ super(PostProcess, self).__init__("postprocess") # load shader self.shader = Shader(shader) dummycam = Camera.instance() # in case this is prior to one being created self.camera = Camera(is_3d=False) self.sprite = LodSprite(z=20.0, w=self.ix, h=self.iy, n=divide) self.sprite.set_2d_size(w=self.ix, h=self.iy) self.alpha = False self.blend = True self.mipmap = mipmap self.tex_list = [self] # TODO check if this self reference causes graphics memory leaks if add_tex: self.tex_list.extend(add_tex)
def _loop_begin(self): # TODO(rec): check if the window was resized and resize it, removing # code from MegaStation to here. if PLATFORM == PLATFORM_WINDOWS: if pygame.event.get(pygame.QUIT): self.destroy() elif PLATFORM != PLATFORM_PI and PLATFORM != PLATFORM_ANDROID: n = xlib.XEventsQueued(self.opengl.d, xlib.QueuedAfterFlush) for i in range(n): if xlib.XCheckMaskEvent(self.opengl.d, KeyPressMask, self.ev): self.event_list.append(self.ev) else: xlib.XNextEvent(self.opengl.d, self.ev) if self.ev.type == ClientMessage: if (self.ev.xclient.data.l[0] == self.opengl.WM_DELETE_WINDOW.value): self.destroy() self.clear() with self.lock: self.sprites_to_load, to_load = set(), self.sprites_to_load self.sprites.extend(to_load) self._for_each_sprite(lambda s: s.load_opengl(), to_load) if MARK_CAMERA_CLEAN_ON_EACH_LOOP: from pi3d.Camera import Camera camera = Camera.instance() if camera is not None: camera.was_moved = False if self.tidy_needed: self._tidy()
def _loop_begin(self): # TODO(rec): check if the window was resized and resize it, removing # code from MegaStation to here. if pi3d.USE_PYGAME: import pygame # although done in __init__ ...python namespaces aarg!!! if pygame.event.get(pygame.QUIT): self.destroy() elif pi3d.PLATFORM != pi3d.PLATFORM_PI and pi3d.PLATFORM != pi3d.PLATFORM_ANDROID: n = xlib.XEventsQueued(self.opengl.d, xlib.QueuedAfterFlush) for i in range(n): if xlib.XCheckMaskEvent(self.opengl.d, KeyPressMask, self.ev): self.event_list.append(self.ev) else: xlib.XNextEvent(self.opengl.d, self.ev) if self.ev.type == ClientMessage: if (self.ev.xclient.data.l[0] == self.opengl.WM_DELETE_WINDOW.value): self.destroy() self.clear() with self.lock: self.sprites_to_load, to_load = set(), self.sprites_to_load self.sprites.extend(to_load) self._for_each_sprite(lambda s: s.load_opengl(), to_load) if MARK_CAMERA_CLEAN_ON_EACH_LOOP: from pi3d.Camera import Camera camera = Camera.instance() if camera is not None: camera.was_moved = False if self.tidy_needed: self._tidy()
def _loop_begin(self): # TODO(rec): check if the window was resized and resize it, removing # code from MegaStation to here. if pi3d.USE_PYGAME: import pygame # although done in __init__ ...python namespaces aarg!!! if pygame.event.get(pygame.QUIT): self.destroy() elif PLATFORM != PLATFORM_PI and PLATFORM != PLATFORM_ANDROID: n = xlib.XEventsQueued(self.opengl.d, xlib.QueuedAfterFlush) for _ in range(n): xlib.XNextEvent(self.opengl.d, self.ev) if self.ev.type == KeyPress or self.ev.type == KeyRelease: self.event_list.append(self.ev) elif self.ev.type == ClientMessage: if (self.ev.xclient.data.l[0] == self.opengl.WM_DELETE_WINDOW.value): self.destroy() self.clear() with self.lock: self.sprites_to_load, to_load = set(), self.sprites_to_load self.sprites.extend(to_load) self._for_each_sprite(lambda s: s.load_opengl(), to_load) if MARK_CAMERA_CLEAN_ON_EACH_LOOP: from pi3d.Camera import Camera #camera = Camera.instance() #if camera is not None: # camera.was_moved = False cameras = Camera.all_instances() if cameras is not None: for camera in cameras: camera.was_moved = False if self.tidy_needed: self._tidy()
def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None, mlist=[], light_camera=None): """If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details. """ self.load_opengl() # really just to set the flag so _unload_opengl runs camera = camera or self._camera or Camera.instance() if not camera.mtrx_made: camera.make_mtrx() if light_camera and not light_camera.mtrx_made: light_camera.make_mtrx() if self.MFlg or len(mlist) > 0 or len(self.children) > 0: # Calculate rotation and translation matrix for this model using numpy. self.MRaw = self.tr1 if self.rozflg: self.MRaw = np.dot(self.roz, self.MRaw) if self.roxflg: self.MRaw = np.dot(self.rox, self.MRaw) if self.royflg: self.MRaw = np.dot(self.roy, self.MRaw) if self.sclflg: self.MRaw = np.dot(self.scl, self.MRaw) if self.tr2flg: self.MRaw = np.dot(self.tr2, self.MRaw) # child drawing addition ############# newmlist = [m for m in mlist] newmlist.append(self.MRaw) if len(self.children) > 0: for c in self.children: c.draw(shader, txtrs, ntl, shny, camera, newmlist, light_camera) # TODO issues where child doesn't use same shader for m in mlist[-1::-1]: self.MRaw = np.dot(self.MRaw, m) ###################################### self.M[0,:,:] = self.MRaw[:,:] #self.M[0:16] = c_floats(self.MRaw.reshape(-1).tolist()) #pypy version self.M[1,:,:] = np.dot(self.MRaw, camera.mtrx)[:,:] #self.M[16:32] = c_floats(np.dot(self.MRaw, camera.mtrx).reshape(-1).tolist()) #pypy if light_camera is not None: self.M[2,:,:] = np.dot(self.MRaw, light_camera.mtrx)[:,:] self.MFlg = False elif camera.was_moved: # Only do this if it's not done because model moved. self.M[1,:,:] = np.dot(self.MRaw, camera.mtrx)[:,:] if light_camera is not None: self.M[2,:,:] = np.dot(self.MRaw, light_camera.mtrx)[:,:] if camera.was_moved: self.unif[18:21] = camera.eye[0:3] for b in self.buf: # Shape.draw has to be passed either parameter == None or values to pass # on. b.draw(self, self.M, self.unif, shader, txtrs, ntl, shny)
def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None, mlist=[], light_camera=None): """If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details. """ self.load_opengl() # really just to set the flag so _unload_opengl runs camera = camera or self._camera or Camera.instance() if not camera.mtrx_made: camera.make_mtrx() if light_camera and not light_camera.mtrx_made: light_camera.make_mtrx() if self.MFlg or len(mlist) > 0 or len(self.children) > 0: # Calculate rotation and translation matrix for this model using numpy. self.MRaw = self.tr1 if self.rozflg: self.MRaw = dot(self.roz, self.MRaw) if self.roxflg: self.MRaw = dot(self.rox, self.MRaw) if self.royflg: self.MRaw = dot(self.roy, self.MRaw) if self.sclflg: self.MRaw = dot(self.scl, self.MRaw) if self.tr2flg: self.MRaw = dot(self.tr2, self.MRaw) # child drawing addition ############# newmlist = [m for m in mlist] newmlist.append(self.MRaw) if len(self.children) > 0: for c in self.children: c.draw(shader, txtrs, ntl, shny, camera, newmlist, light_camera) # TODO issues where child doesn't use same shader for m in mlist[-1::-1]: self.MRaw = dot(self.MRaw, m) ###################################### self.M[0,:,:] = self.MRaw[:,:] #self.M[0:16] = c_floats(self.MRaw.reshape(-1).tolist()) #pypy version self.M[1,:,:] = dot(self.MRaw, camera.mtrx)[:,:] #self.M[16:32] = c_floats(dot(self.MRaw, camera.mtrx).reshape(-1).tolist()) #pypy if light_camera is not None: self.M[2,:,:] = dot(self.MRaw, light_camera.mtrx)[:,:] self.MFlg = False elif camera.was_moved: # Only do this if it's not done because model moved. self.M[1,:,:] = dot(self.MRaw, camera.mtrx)[:,:] if light_camera is not None: self.M[2,:,:] = dot(self.MRaw, light_camera.mtrx)[:,:] if camera.was_moved: self.unif[18:21] = camera.eye[0:3] for b in self.buf: # Shape.draw has to be passed either parameter == None or values to pass # on. b.draw(self, self.M, self.unif, shader, txtrs, ntl, shny)
def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None, mlist=[]): """If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details. """ self.load_opengl( ) # really just to set the flag so _unload_opengl runs from pi3d.Camera import Camera camera = camera or self._camera or Camera.instance() shader = shader or self.shader shader.use() if self.MFlg == True or len(mlist): # Calculate rotation and translation matrix for this model using numpy. self.MRaw = dot( self.tr2, dot(self.scl, dot(self.roy, dot(self.rox, dot(self.roz, self.tr1))))) # child drawing addition ############# newmlist = [m for m in mlist] newmlist.append(self.MRaw) if len(self.children) > 0: for c in self.children: c.draw(shader, txtrs, ntl, shny, camera, newmlist) for m in mlist[-1::-1]: self.MRaw = dot(self.MRaw, m) ###################################### self.M[0:16] = self.MRaw.ravel() #self.M[0:16] = c_floats(self.MRaw.reshape(-1).tolist()) #pypy version self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() #self.M[16:32] = c_floats(dot(self.MRaw, camera.mtrx).reshape(-1).tolist()) #pypy self.MFlg = False elif camera.was_moved: # Only do this if it's not done because model moved. self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() if camera.was_moved: self.unif[18:21] = camera.eye[0:3] opengles.glUniformMatrix4fv(shader.unif_modelviewmatrix, 2, ctypes.c_int(0), ctypes.byref(self.M)) opengles.glUniform3fv(shader.unif_unif, 20, ctypes.byref(self.unif)) for b in self.buf: # Shape.draw has to be passed either parameter == None or values to pass # on. b.draw(self, shader, txtrs, ntl, shny)
def __init__(self, shader="post_base", mipmap=False, add_tex=None, scale=1.0, camera=None, divide=1): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *add_tex* list of textures. If additional textures can be used by the shader then they can be added here. *scale* will only render this proportion of the full screen which will then be mapped to the full uv of the Sprite. The camera object passed (below) will need to have the same scale set to avoid perspective distortion *camera* the camera to use for rendering to the offscreen texture *divide* allow the sprite to be created with intermediate vertices to allow interesting vertex shader effects """ super(PostProcess, self).__init__("postprocess") self.scale = scale # load shader self.shader = Shader(shader) if camera is None: self.viewcam = Camera.instance() # in case this is prior to one being created else: self.viewcam = camera self.camera = Camera(is_3d=False) self.sprite = LodSprite(z=20.0, w=self.ix, h=self.iy, n=divide) self.sprite.set_2d_size(w=self.ix, h=self.iy) for b in self.sprite.buf: b.unib[6] = self.scale # ufact b.unib[7] = self.scale # vfact b.unib[9] = (1.0 - self.scale) * 0.5 # uoffset b.unib[10] = (1.0 - self.scale) * 0.5 # voffset self.alpha = False self.blend = True self.mipmap = mipmap self.tex_list = [self] # TODO check if this self reference causes graphics memory leaks if add_tex: self.tex_list.extend(add_tex)
def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None, mlist=[]): """If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details. """ self.load_opengl() # really just to set the flag so _unload_opengl runs from pi3d.Camera import Camera camera = camera or self._camera or Camera.instance() shader = shader or self.shader shader.use() if self.MFlg == True or len(mlist): # Calculate rotation and translation matrix for this model using numpy. self.MRaw = dot(self.tr2, dot(self.scl, dot(self.roy, dot(self.rox, dot(self.roz, self.tr1))))) # child drawing addition ############# newmlist = [m for m in mlist] newmlist.append(self.MRaw) if len(self.children) > 0: for c in self.children: c.draw(shader, txtrs, ntl, shny, camera, newmlist) for m in mlist[-1::-1]: self.MRaw = dot(self.MRaw, m) ###################################### self.M[0:16] = self.MRaw.ravel() #self.M[0:16] = c_floats(self.MRaw.reshape(-1).tolist()) #pypy version self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() #self.M[16:32] = c_floats(dot(self.MRaw, camera.mtrx).reshape(-1).tolist()) #pypy self.MFlg = False elif camera.was_moved: # Only do this if it's not done because model moved. self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() if camera.was_moved: self.unif[18:21] = camera.eye[0:3] opengles.glUniformMatrix4fv(shader.unif_modelviewmatrix, 2, ctypes.c_int(0), ctypes.byref(self.M)) opengles.glUniform3fv(shader.unif_unif, 20, ctypes.byref(self.unif)) for b in self.buf: # Shape.draw has to be passed either parameter == None or values to pass # on. b.draw(self, shader, txtrs, ntl, shny)
def __init__(self, position, light, scale=10.0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") self.LIGHT_CAM = Camera(is_3d=False, scale=scale) l_p = light.lightpos l_len = (l_p[0]**2 + l_p[1]**2 + l_p[2]**2)**0.5 self.OFFSET = [200.0 * i / l_len for i in l_p] self.LIGHT_CAM.position([position[i] - o for i, o in enumerate(self.OFFSET)]) self.tilt, self.rot = self.LIGHT_CAM.point_at(position) self.cast_shader = Shader("shadowcast")
class ShadowCaster(OffScreenTexture): """For creating a depth-of-field blurring effect on selected objects""" def __init__(self, position, light, scale=10.0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") self.LIGHT_CAM = Camera(is_3d=False, scale=scale) l_p = light.lightpos l_len = (l_p[0]**2 + l_p[1]**2 + l_p[2]**2)**0.5 self.OFFSET = [200.0 * i / l_len for i in l_p] self.LIGHT_CAM.position([position[i] - o for i, o in enumerate(self.OFFSET)]) self.tilt, self.rot = self.LIGHT_CAM.point_at(position) self.cast_shader = Shader("shadowcast") def move_light(self, position): self.LIGHT_CAM.reset() self.LIGHT_CAM.rotate(self.tilt, self.rot, 0) self.LIGHT_CAM.position([position[i] - o for i, o in enumerate(self.OFFSET)]) def start_cast(self, position=None): if position is not None: self.move_light(position) super(ShadowCaster, self)._start() def cast_shadow(self, shape): shape.draw(shader=self.cast_shader, light_camera=self.LIGHT_CAM) def end_cast(self): super(ShadowCaster, self)._end() def draw_shadow(self): self.emap.draw(shader=self.dshader) def draw_tree(self, tree, shader): tree.draw(shader, [self])
def _loop_begin(self): # TODO(rec): check if the window was resized and resize it, removing # code from MegaStation to here. self.clear() with self.lock: self.sprites_to_load, to_load = set(), self.sprites_to_load self.sprites.extend(to_load) self._for_each_sprite(lambda s: s.load_opengl(), to_load) if MARK_CAMERA_CLEAN_ON_EACH_LOOP: from pi3d.Camera import Camera camera = Camera.instance() if camera: camera.was_moved = False
def __init__(self, emap, light): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") # load shader for casting shadows and camera self.cshader = Shader("uv_flat") self.mshader = Shader("mat_flat") # keep copy of ElevationMap self.emap = emap self.emap.set_material((0.0, 0.0, 0.0)) # hide bits below ground # TODO doesn't cope with z light positions self.eye = [-500 * i for i in light.lightpos] # good distance away if self.eye[1] <= 0: # must have +ve y self.eye[1] = 500.0 if abs(self.eye[0]) > abs(self.eye[2]): # x val is bigger than z val # change scale so map just fits on screen if self.eye[0] < 0: su, sv = 1.0, 1.0 else: su, sv = -1.0, -1.0 self.scaleu = float(self.iy) / self.emap.width self.scalev = float(self.ix) / self.emap.depth self.eye[2] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[0] ** 2 + self.eye[1] ** 2) ** 0.5 self.emap.unif[50] = 1.0 # orientation flag self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[0] / float(self.eye[1]) # height adjustment else: # change scale so map just fits on screen if self.eye[2] < 0: su, sv = 1.0, -1.0 else: su, sv = -1.0, 1.0 self.scaleu = float(self.iy) / self.emap.depth self.scalev = float(self.ix) / self.emap.width self.eye[0] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[2] ** 2 + self.eye[1] ** 2) ** 0.5 self.emap.unif[50] = 0.0 self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[2] / float(self.eye[1]) if abs(self.scaleu) > abs(self.scalev): self.scale = 3.0 * self.scalev # multiplication factor to reduce pixeliness else: self.scale = 3.0 * self.scaleu self.scaleu = su * self.scale / self.scaleu # reused later in end_cast self.scalev = sv * self.scale / self.scalev self.camera0 = Camera() # default instance created as normal, just in case! self.camera = Camera(is_3d=False, eye=self.eye, scale=self.scale) # load shader for drawing map with shadows self.dshader = Shader("shadowcast")
class ShadowCaster(OffScreenTexture): """For creating a depth-of-field blurring effect on selected objects""" def __init__(self, position, light, scale=10.0, ix=None, iy=None): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") self.LIGHT_CAM = Camera(is_3d=False, scale=scale) l_p = light.lightpos l_len = (l_p[0]**2 + l_p[1]**2 + l_p[2]**2)**0.5 self.OFFSET = [200.0 * i / l_len for i in l_p] self.OFFSET[0] = -self.OFFSET[0] self.OFFSET[2] = -self.OFFSET[2] self.LIGHT_CAM.position( [position[i] - o for i, o in enumerate(self.OFFSET)]) self.tilt, self.rot = self.LIGHT_CAM.point_at(position) self.cast_shader = Shader("shadowcast") def move_light(self, position): self.LIGHT_CAM.reset() self.LIGHT_CAM.rotate(self.tilt, self.rot, 0) self.LIGHT_CAM.position( [position[i] - o for i, o in enumerate(self.OFFSET)]) def start_cast(self, position=None): if position is not None: self.move_light(position) super(ShadowCaster, self)._start() def cast_shadow(self, shape): shape.draw(shader=self.cast_shader, light_camera=self.LIGHT_CAM) def end_cast(self): super(ShadowCaster, self)._end() def draw_shadow(self): self.emap.draw(shader=self.dshader) def draw_tree(self, tree, shader): tree.draw(shader, [self])
def rotate_to_direction(self, direction, forward=[0.0, 0.0, 1.0]): """ works out the XYZ euler rotations to rotate this shape from forward to direction vectors Arguments: *direction* 3vector tuple, array or numpy array *forward* 3vector, usually +ve z direction """ if type(direction) is not np.ndarray: direction = np.array(direction) if type(forward) is not np.ndarray: forward = np.array(forward) if self._camera is None: self._camera = Camera.instance() # TODO may be issues doing this not in main thread (otherwise why not in Shape.__init__()?) rot_mtrix = self._camera.matrix_from_two_vectors(forward, direction) rot_euler = self._camera.euler_angles(rot_mtrix) self.rotateToX(-rot_euler[0]) # unclear why x and y need to be -ve self.rotateToY(-rot_euler[1]) # something to do with sense of rotation of camera self.rotateToZ(rot_euler[2])
def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None): """If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details. """ from pi3d.Camera import Camera camera = camera or self._camera or Camera.instance() shader = shader or self.shader shader.use() if self.MFlg == True: # Calculate rotation and translation matrix for this model using numpy. self.MRaw = dot(self.tr2, dot(self.scl, dot(self.roy, dot(self.rox, dot(self.roz, self.tr1))))) self.M[0:16] = self.MRaw.ravel() self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() self.MFlg = False elif camera.was_moved: # Only do this if it's not done because model moved. self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() if camera.was_moved: self.unif[18:21] = camera.eye[0:3] opengles.glUniformMatrix4fv(shader.unif_modelviewmatrix, 2, ctypes.c_int(0), ctypes.byref(self.M)) opengles.glUniform3fv(shader.unif_unif, 20, ctypes.byref(self.unif)) for b in self.buf: # Shape.draw has to be passed either parameter == None or values to pass # on. b.draw(shader, txtrs, ntl, shny)
def rotate_to_direction(self, direction, forward=[0.0, 0.0, 1.0]): """ works out the XYZ euler rotations to rotate this shape from forward to direction vectors Arguments: *direction* 3vector tuple, array or numpy array *forward* 3vector, usually +ve z direction """ if type(direction) is not np.ndarray: direction = np.array(direction) if type(forward) is not np.ndarray: forward = np.array(forward) if self._camera is None: self._camera = Camera.instance( ) # TODO may be issues doing this not in main thread (otherwise why not in Shape.__init__()?) rot_mtrix = self._camera.matrix_from_two_vectors(forward, direction) rot_euler = self._camera.euler_angles(rot_mtrix) self.rotateToX(-rot_euler[0]) # unclear why x and y need to be -ve self.rotateToY( -rot_euler[1]) # something to do with sense of rotation of camera self.rotateToZ(rot_euler[2])
def __init__(self, shader="uv_flat", mipmap=False, separation=0.4): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. """ # load shader self.shader = Shader(shader) self.camera_3d = Camera() self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="bin")) ix, iy = self.textures[i].ix, self.textures[i].iy #two sprites full width but moved so that they are centred on the #left and right edges. The offset values then move the uv mapping #so the image is on the right of the left sprite and left of the #right sprite self.sprites.append(Sprite(z=20.0, x=-ix/2.0 + i*ix, w=ix, h=iy, flip=True)) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) self.textures[i].alpha = False self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append([self.textures[i]])
def draw(self, shader=None, txtrs=None, ntl=None, shny=None, camera=None): """If called without parameters, there has to have been a previous call to set_draw_details() for each Buffer in buf[]. NB there is no facility for setting umult and vmult with draw: they must be set using set_draw_details or Buffer.set_draw_details. """ from pi3d.Camera import Camera camera = camera or self._camera or Camera.instance() shader = shader or self.shader shader.use() if self.MFlg == True: # Calculate rotation and translation matrix for this model using numpy. self.MRaw = dot( self.tr2, dot(self.scl, dot(self.roy, dot(self.rox, dot(self.roz, self.tr1))))) self.M[0:16] = self.MRaw.ravel() self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() self.MFlg = False elif camera.was_moved: # Only do this if it's not done because model moved. self.M[16:32] = dot(self.MRaw, camera.mtrx).ravel() if camera.was_moved: self.unif[18:21] = camera.eye[0:3] opengles.glUniformMatrix4fv(shader.unif_modelviewmatrix, 2, ctypes.c_int(0), ctypes.byref(self.M)) opengles.glUniform3fv(shader.unif_unif, 20, ctypes.byref(self.unif)) for b in self.buf: # Shape.draw has to be passed either parameter == None or values to pass # on. b.draw(shader, txtrs, ntl, shny)
def __init__(self, shader="uv_flat", mipmap=False, separation=0.4, interlace=0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. *interlace* if interlace > 0 then the images are not taken with glScissor and must be drawn with a special interlacing shader. """ # load shader if interlace <= 0: self.shader = Shader(shader) else: self.shader = Shader( vshader_source=""" precision mediump float; attribute vec3 vertex; attribute vec2 texcoord; uniform mat4 modelviewmatrix[2]; varying vec2 texcoordout; void main(void) { texcoordout = texcoord; gl_Position = modelviewmatrix[1] * vec4(vertex,1.0); } """, fshader_source=""" precision mediump float; uniform sampler2D tex0; uniform sampler2D tex1; varying vec2 texcoordout; void main(void) {{ vec4 texc0 = texture2D(tex0, texcoordout); vec4 texc1 = texture2D(tex1, texcoordout); vec2 coord = vec2(gl_FragCoord); gl_FragColor = mix(texc0, texc1, step(0.5, fract(coord.x / {:f}))); }} """.format( interlace * 2.0 ), ) # self.shader = Shader("2d_flat") self.camera_3d = Camera() self.forMtrx = np.identity(4, dtype="float32") # initially not rotated self.position = [0.0, 0.0, 0.0] self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.interlace = interlace self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="stereo")) ix, iy = self.textures[i].ix, self.textures[i].iy # two sprites full width but moved so that they are centred on the # left and right edges. The offset values then move the uv mapping # so the image is on the right of the left sprite and left of the # right sprite self.sprites.append(Sprite(z=20.0, w=ix, h=iy, flip=True)) if interlace <= 0: self.sprites[i].positionX(-ix / 2.0 + i * ix) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) else: self.sprites[i].set_2d_size(w=ix, h=iy) self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append(self.textures[i]) opengles.glColorMask(1, 1, 1, 1)
class StereoCam(object): """For creating an apparatus with two sprites to hold left and right eye views. This Class is used to hold the 3D Camera which should be used to draw the 3D objects. It also holds a 2D Camera for drawing the Sprites""" def __init__(self, shader="uv_flat", mipmap=False, separation=0.4, interlace=0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. *interlace* if interlace > 0 then the images are not taken with glScissor and must be drawn with a special interlacing shader. """ # load shader if interlace <= 0: self.shader = Shader(shader) else: self.shader = Shader( vshader_source=""" precision mediump float; attribute vec3 vertex; attribute vec2 texcoord; uniform mat4 modelviewmatrix[2]; varying vec2 texcoordout; void main(void) { texcoordout = texcoord; gl_Position = modelviewmatrix[1] * vec4(vertex,1.0); } """, fshader_source=""" precision mediump float; uniform sampler2D tex0; uniform sampler2D tex1; varying vec2 texcoordout; void main(void) {{ vec4 texc0 = texture2D(tex0, texcoordout); vec4 texc1 = texture2D(tex1, texcoordout); vec2 coord = vec2(gl_FragCoord); gl_FragColor = mix(texc0, texc1, step(0.5, fract(coord.x / {:f}))); }} """.format( interlace * 2.0 ), ) # self.shader = Shader("2d_flat") self.camera_3d = Camera() self.forMtrx = np.identity(4, dtype="float32") # initially not rotated self.position = [0.0, 0.0, 0.0] self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.interlace = interlace self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="stereo")) ix, iy = self.textures[i].ix, self.textures[i].iy # two sprites full width but moved so that they are centred on the # left and right edges. The offset values then move the uv mapping # so the image is on the right of the left sprite and left of the # right sprite self.sprites.append(Sprite(z=20.0, w=ix, h=iy, flip=True)) if interlace <= 0: self.sprites[i].positionX(-ix / 2.0 + i * ix) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) else: self.sprites[i].set_2d_size(w=ix, h=iy) self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append(self.textures[i]) opengles.glColorMask(1, 1, 1, 1) def move_camera(self, position, rot, tilt, roll=0.0, absolute=True): """ Arguments: *position* array [x,y,z] *rot, tilt, roll* rotations about y, x, z axis (yes it's not entirely logical for position to be an array and orientation three values but it's too late to change!) *absolute* if set to False then the rotations are treated as relative to the rotated frame of reference i.e. as if signals from VR headset 3 axis gyro. """ self.camera_3d.rotate(tilt, rot, roll) self.camera_3d.position(position) self.camera_3d.absolute = absolute def start_capture(self, side): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. *side* Either 0 or 1 to determine stereoscopic view """ self.camera_3d.reset() offs = -self.offs if side == 0 else self.offs self.camera_3d.offset([offs, 0.0, 0.0]) # self.camera_3d.mtrx = np.dot(self.forMtrx, self.camera_3d.mtrx) # self.camera_3d.position(self.position) tex = self.textures[side] tex._start() if self.interlace <= 0: xx = tex.ix / 4.0 # draw the middle only - half width yy = 0 ww = tex.ix / 2.0 hh = tex.iy opengles.glEnable(GL_SCISSOR_TEST) opengles.glScissor( ctypes.c_int(int(xx)), ctypes.c_int(int(yy)), ctypes.c_int(int(ww)), ctypes.c_int(int(hh)) ) def end_capture(self, side): """ stop capturing to texture and resume normal rendering to default """ self.textures[side]._end() if self.interlace <= 0: opengles.glDisable(GL_SCISSOR_TEST) def draw(self): """ draw the shape using the saved texture """ if self.interlace <= 0: for i in range(2): self.sprites[i].draw(self.shader, [self.tex_list[i]], 0.0, 0.0, self.camera_2d) else: self.sprites[0].draw(self.shader, self.tex_list, 0.0, 0.0, self.camera_2d) def get_direction(self): return self.camera_3d.get_direction()
class StereoCam(object): """For creating an apparatus with two sprites to hold left and right eye views. This Class is used to hold the 3D Camera which should be used to draw the 3D objects. It also holds a 2D Camera for drawing the Sprites""" def __init__(self, shader="uv_flat", mipmap=False, separation=0.4, interlace=0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to uv_flat. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. *interlace* if interlace > 0 then the images are not taken with glScissor and must be drawn with a special interlacing shader. """ # load shader if interlace <= 0: # i.e. default side by side behaviour self.shader = Shader.create(shader) else: self.shader = Shader(vshader_source = """ precision mediump float; attribute vec3 vertex; attribute vec2 texcoord; uniform mat4 modelviewmatrix[2]; varying vec2 texcoordout; void main(void) { texcoordout = texcoord; gl_Position = modelviewmatrix[1] * vec4(vertex,1.0); } """, fshader_source = """ precision mediump float; uniform sampler2D tex0; uniform sampler2D tex1; varying vec2 texcoordout; void main(void) {{ vec4 texc0 = texture2D(tex0, texcoordout); vec4 texc1 = texture2D(tex1, texcoordout); vec2 coord = vec2(gl_FragCoord); gl_FragColor = mix(texc0, texc1, step(0.5, fract(coord.x / {:f}))); }} """.format(interlace * 2.0)) self.camera_3d = Camera() # create 3d cam first so it becomes default instance self.forMtrx = np.identity(4, dtype='float32') # initially not rotated self.position = [0.0, 0.0, 0.0] self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.interlace = interlace self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="stereo")) ix, iy = self.textures[i].ix, self.textures[i].iy #two sprites full width but moved so that they are centred on the #left and right edges. The offset values then move the uv mapping #so the image is on the right of the left sprite and left of the #right sprite self.sprites.append(Sprite(z=20.0, w=ix, h=iy, flip=True)) if interlace <= 0: self.sprites[i].positionX(-ix/2.0 + i*ix) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) else: self.sprites[i].set_2d_size(w=ix, h=iy) self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append(self.textures[i]) opengles.glColorMask(1, 1, 1, 1) def move_camera(self, position, rot, tilt, roll=0.0, absolute=True): ''' Arguments: *position* array [x,y,z] *rot, tilt, roll* rotations about y, x, z axis (yes it's not entirely logical for position to be an array and orientation three values but it's too late to change!) *absolute* if set to False then the rotations are treated as relative to the rotated frame of reference i.e. as if signals from VR headset 3 axis gyro. ''' self.camera_3d.rotate(tilt, rot, roll) self.camera_3d.position(position) self.camera_3d.absolute = absolute def start_capture(self, side): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. *side* Either 0 or 1 to determine stereoscopic view """ self.camera_3d.reset() offs = -self.offs if side == 0 else self.offs self.camera_3d.offset([offs, 0.0, 0.0]) #self.camera_3d.mtrx = np.dot(self.forMtrx, self.camera_3d.mtrx) #self.camera_3d.position(self.position) tex = self.textures[side] tex._start() if self.interlace <= 0: xx = tex.ix / 4.0 # draw the middle only - half width yy = 0 ww = tex.ix / 2.0 hh = tex.iy opengles.glEnable(GL_SCISSOR_TEST) opengles.glScissor(GLint(int(xx)), GLint(int(yy)), GLsizei(int(ww)), GLsizei(int(hh))) def end_capture(self, side): """ stop capturing to texture and resume normal rendering to default """ self.textures[side]._end() if self.interlace <= 0: opengles.glDisable(GL_SCISSOR_TEST) def draw(self): """ draw the shape using the saved texture """ if self.interlace <= 0: for i in range(2): self.sprites[i].draw(self.shader, [self.tex_list[i].color], 0.0, 0.0, self.camera_2d) else: self.sprites[0].draw(self.shader, [t.color for t in self.tex_list], 0.0, 0.0, self.camera_2d) def get_direction(self): return self.camera_3d.get_direction()
class ShadowCaster(OffScreenTexture): """For creating a depth-of-field blurring effect on selected objects""" def __init__(self, emap, light): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") # load shader for casting shadows and camera self.cshader = Shader("uv_flat") self.mshader = Shader("mat_flat") # keep copy of ElevationMap self.emap = emap self.emap.set_material((0.0, 0.0, 0.0)) # hide bits below ground #TODO doesn't cope with z light positions self.eye = [-500.0 * i for i in light.lightpos] # good distance away if self.eye[1] <= 0: # must have +ve y self.eye[1] = 500.0 if abs(self.eye[0]) > abs(self.eye[2]): #x val is bigger than z val #change scale so map just fits on screen if self.eye[0] < 0: su, sv = 1.0, 1.0 else: su, sv = -1.0, -1.0 self.scaleu = float(self.iy) / self.emap.width self.scalev = float(self.ix)/ self.emap.depth self.eye[2] = 0 self.scaleu = self.scaleu / self.eye[1] * (self.eye[0]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 1.0 #orientation flag self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[0] / self.eye[1] #height adjustment else: #change scale so map just fits on screen if self.eye[2] < 0: su, sv = 1.0, -1.0 else: su, sv = -1.0, 1.0 self.scaleu = float(self.iy) / self.emap.depth self.scalev = float(self.ix)/ self.emap.width self.eye[0] = 0 self.scaleu = self.scaleu / self.eye[1] * (self.eye[2]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 0.0 self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[2] / self.eye[1] if abs(self.scaleu) > abs(self.scalev): self.scale = 3.0 * self.scalev # multiplication factor to reduce pixeliness else: self.scale = 3.0 * self.scaleu self.scaleu = su * self.scale / self.scaleu # reused later in end_cast self.scalev = sv * self.scale / self.scalev self.camera0 = Camera() # default instance created as normal, just in case! self.camera = Camera(is_3d=False, eye=self.eye, scale=self.scale) # load shader for drawing map with shadows self.dshader = Shader("shadowcast") def start_cast(self, location=(0.0, 0.0, 0.0)): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. If you want blurred edges you will have to capture the rendering of an object and its background then re-draw them using the blur() method. Large objects will obviously take a while to draw and re-draw """ opengles.glClearColor(ctypes.c_float(0.0), ctypes.c_float(0.0), ctypes.c_float(0.0), ctypes.c_float(1.0)) super(ShadowCaster, self)._start() self.camera.reset(is_3d=False, scale=self.scale) self.camera.position((location[0], 0, location[2])) self.location = location def end_cast(self): """ stop capturing to texture and resume normal rendering to default """ #draw the actual map self.emap.draw(shader=self.mshader, camera=self.camera) super(ShadowCaster, self)._end() # set third texture to this ShadowCaster texture texs = self.emap.buf[0].textures if len(texs) == 2: texs.append(self) else: texs[2] = self # change background back to blue opengles.glClearColor(ctypes.c_float(0.4), ctypes.c_float(0.8), ctypes.c_float(0.8), ctypes.c_float(1.0)) # work out left, top, right, bottom for shader self.emap.unif[48] = 0.5 * (1.0 + self.scaleu) # left [16][0] self.emap.unif[49] = 0.5 * (1.0 + self.scalev) # top [16][1] self.emap.unif[51] = 1.0 - self.emap.unif[48] # right [17][0] self.emap.unif[52] = 1.0 - self.emap.unif[49] # bottom [17][1] du = float(self.location[0] / self.emap.width) dv = float(self.location[2] / self.emap.depth) self.emap.unif[48] -= self.scaleu * (du if self.emap.unif[50] == 1.0 else dv) self.emap.unif[49] += self.scalev * (dv if self.emap.unif[50] == 1.0 else du) self.emap.unif[51] -= self.scaleu * (du if self.emap.unif[50] == 1.0 else dv) self.emap.unif[52] += self.scalev * (dv if self.emap.unif[50] == 1.0 else du) def add_shadow(self, shape): shape.draw(shader=self.cshader, camera=self.camera) def draw_shadow(self): self.emap.draw(shader=self.dshader)
def __init__(self, emap, light): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") from pi3d.Display import Display self.ix, self.iy = Display.INSTANCE.width, Display.INSTANCE.height self.im = Image.new("RGBA",(self.ix, self.iy)) self.image = self.im.convert("RGBA").tostring('raw', "RGBA") self.alpha = True self.blend = False self._tex = ctypes.c_int() self.framebuffer = (ctypes.c_int * 1)() opengles.glGenFramebuffers(1, self.framebuffer) self.depthbuffer = (ctypes.c_int * 1)() opengles.glGenRenderbuffers(1, self.depthbuffer) # load shader for casting shadows and camera self.cshader = Shader("shaders/uv_flat") self.mshader = Shader("shaders/mat_flat") # keep copy of ElevationMap self.emap = emap self.emap.set_material((0.0, 0.0, 0.0)) # hide bits below ground #TODO doesn't cope with z light positions self.eye = [-500*i for i in light.lightpos] # good distance away if self.eye[1] <= 0: # must have +ve y self.eye[1] = 500.0 if abs(self.eye[0]) > abs(self.eye[2]): #x val is bigger than z val #change scale so map just fits on screen if self.eye[0] < 0: su, sv = 1.0, 1.0 else: su, sv = -1.0, -1.0 self.scaleu = float(self.iy) / self.emap.width self.scalev = float(self.ix)/ self.emap.depth self.eye[2] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[0]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 1.0 #orientation flag self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[0] / float(self.eye[1]) #height adjustment else: #change scale so map just fits on screen if self.eye[2] < 0: su, sv = 1.0, -1.0 else: su, sv = -1.0, 1.0 self.scaleu = float(self.iy) / self.emap.depth self.scalev = float(self.ix)/ self.emap.width self.eye[0] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[2]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 0.0 self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[2] / float(self.eye[1]) if abs(self.scaleu) > abs(self.scalev): self.scale = 3.0 * self.scalev # multiplication factor to reduce pixeliness else: self.scale = 3.0 * self.scaleu self.scaleu = su * self.scale / self.scaleu # reused later in end_cast self.scalev = sv * self.scale / self.scalev self.camera0 = Camera() # default instance created as normal, just in case! self.camera = Camera(is_3d=False, eye=self.eye, scale=self.scale) # load shader for drawing map with shadows self.dshader = Shader("shaders/shadowcast")
class StereoCam(object): """For creating an apparatus with two sprites to hold left and right eye views. This Class is used to hold the 3D Camera which should be used to draw the 3D objects. It also holds a 2D Camera for drawing the Sprites""" def __init__(self, shader="uv_flat", mipmap=False, separation=0.4, interlace=0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. *interlace* if interlace > 0 then the images are not taken with glScissor and must be drawn with a special interlacing shader. """ # load shader if interlace <= 0: self.shader = Shader(shader) else: self.shader = Shader(vshader_source = """ precision mediump float; attribute vec3 vertex; attribute vec2 texcoord; uniform mat4 modelviewmatrix[2]; varying vec2 texcoordout; void main(void) { texcoordout = texcoord; gl_Position = modelviewmatrix[1] * vec4(vertex,1.0); } """, fshader_source = """ precision mediump float; uniform sampler2D tex0; uniform sampler2D tex1; varying vec2 texcoordout; void main(void) {{ vec4 texc0 = texture2D(tex0, texcoordout); vec4 texc1 = texture2D(tex1, texcoordout); vec2 coord = vec2(gl_FragCoord); gl_FragColor = mix(texc0, texc1, step(0.5, fract(coord.x / {:f}))); }} """.format(interlace * 2.0)) #self.shader = Shader("2d_flat") self.camera_3d = Camera() self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.interlace = interlace self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="stereo")) ix, iy = self.textures[i].ix, self.textures[i].iy #two sprites full width but moved so that they are centred on the #left and right edges. The offset values then move the uv mapping #so the image is on the right of the left sprite and left of the #right sprite self.sprites.append(Sprite(z=20.0, w=ix, h=iy, flip=True)) if interlace <= 0: self.sprites[i].positionX(-ix/2.0 + i*ix) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) else: self.sprites[i].set_2d_size(w=ix, h=iy) self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append(self.textures[i]) def move_camera(self, position, rot, tilt): self.camera_3d.reset() self.camera_3d.rotate(tilt, rot, 0) self.camera_3d.position(position) def start_capture(self, side): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. *side* Either 0 or 1 to determine stereoscopic view """ offs = -self.offs if side == 0 else self.offs self.camera_3d.position((self.camera_3d.mtrx[2,3] * offs, 0, -self.camera_3d.mtrx[0,3] * offs)) tex = self.textures[side] tex._start() if self.interlace <= 0: xx = tex.ix / 4.0 # draw the middle only - half width yy = 0 ww = tex.ix / 2.0 hh = tex.iy opengles.glEnable(GL_SCISSOR_TEST) opengles.glScissor(ctypes.c_int(int(xx)), ctypes.c_int(int(yy)), ctypes.c_int(int(ww)), ctypes.c_int(int(hh))) def end_capture(self, side): """ stop capturing to texture and resume normal rendering to default """ self.textures[side]._end() if self.interlace <= 0: opengles.glDisable(GL_SCISSOR_TEST) def draw(self): """ draw the shape using the saved texture """ if self.interlace <= 0: for i in range(2): self.sprites[i].draw(self.shader, [self.tex_list[i]], 0.0, 0.0, self.camera_2d) else: self.sprites[0].draw(self.shader, self.tex_list, 0.0, 0.0, self.camera_2d)
def cameraY(self,y): self.vrcamyloc = y from pi3d.Camera import Camera vrcamera = Camera.instance() if vrcamera: vrcamera.position((self.vrcamxloc,self.vrcamyloc,1.0))
class ShadowCaster(OffScreenTexture): """For creating a depth-of-field blurring effect on selected objects""" def __init__(self, emap, light): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") # load shader for casting shadows and camera self.cshader = Shader("uv_flat") self.mshader = Shader("mat_flat") # keep copy of ElevationMap self.emap = emap self.emap.set_material((0.0, 0.0, 0.0)) # hide bits below ground # TODO doesn't cope with z light positions self.eye = [-500 * i for i in light.lightpos] # good distance away if self.eye[1] <= 0: # must have +ve y self.eye[1] = 500.0 if abs(self.eye[0]) > abs(self.eye[2]): # x val is bigger than z val # change scale so map just fits on screen if self.eye[0] < 0: su, sv = 1.0, 1.0 else: su, sv = -1.0, -1.0 self.scaleu = float(self.iy) / self.emap.width self.scalev = float(self.ix) / self.emap.depth self.eye[2] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[0] ** 2 + self.eye[1] ** 2) ** 0.5 self.emap.unif[50] = 1.0 # orientation flag self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[0] / float(self.eye[1]) # height adjustment else: # change scale so map just fits on screen if self.eye[2] < 0: su, sv = 1.0, -1.0 else: su, sv = -1.0, 1.0 self.scaleu = float(self.iy) / self.emap.depth self.scalev = float(self.ix) / self.emap.width self.eye[0] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[2] ** 2 + self.eye[1] ** 2) ** 0.5 self.emap.unif[50] = 0.0 self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[2] / float(self.eye[1]) if abs(self.scaleu) > abs(self.scalev): self.scale = 3.0 * self.scalev # multiplication factor to reduce pixeliness else: self.scale = 3.0 * self.scaleu self.scaleu = su * self.scale / self.scaleu # reused later in end_cast self.scalev = sv * self.scale / self.scalev self.camera0 = Camera() # default instance created as normal, just in case! self.camera = Camera(is_3d=False, eye=self.eye, scale=self.scale) # load shader for drawing map with shadows self.dshader = Shader("shadowcast") def start_cast(self, location=(0.0, 0.0, 0.0)): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. If you want blurred edges you will have to capture the rendering of an object and its background then re-draw them using the blur() method. Large objects will obviously take a while to draw and re-draw """ opengles.glClearColor(ctypes.c_float(0.0), ctypes.c_float(0.0), ctypes.c_float(0.0), ctypes.c_float(1.0)) super(ShadowCaster, self)._start() self.camera.reset(is_3d=False, scale=self.scale) self.camera.position((location[0], 0, location[2])) self.location = location def end_cast(self): """ stop capturing to texture and resume normal rendering to default """ # draw the actual map self.emap.draw(shader=self.mshader, camera=self.camera) super(ShadowCaster, self)._end() # set third texture to this ShadowCaster texture texs = self.emap.buf[0].textures if len(texs) == 2: texs.append(self) else: texs[2] = self # change background back to blue opengles.glClearColor(ctypes.c_float(0.4), ctypes.c_float(0.8), ctypes.c_float(0.8), ctypes.c_float(1.0)) # work out left, top, right, bottom for shader self.emap.unif[48] = 0.5 * (1.0 + self.scaleu) # left [16][0] self.emap.unif[49] = 0.5 * (1.0 + self.scalev) # top [16][1] self.emap.unif[51] = 1.0 - self.emap.unif[48] # right [17][0] self.emap.unif[52] = 1.0 - self.emap.unif[49] # bottom [17][1] du = float(self.location[0] / self.emap.width) dv = float(self.location[2] / self.emap.depth) self.emap.unif[48] -= self.scaleu * (du if self.emap.unif[50] == 1.0 else dv) self.emap.unif[49] += self.scalev * (dv if self.emap.unif[50] == 1.0 else du) self.emap.unif[51] -= self.scaleu * (du if self.emap.unif[50] == 1.0 else dv) self.emap.unif[52] += self.scalev * (dv if self.emap.unif[50] == 1.0 else du) def add_shadow(self, shape): shape.draw(shader=self.cshader, camera=self.camera) def draw_shadow(self): self.emap.draw(shader=self.dshader)
from pi3d.shape.Sphere import Sphere from pi3d.util.String import String from pi3d.util.Screenshot import screenshot from pi3d.util.Defocus import Defocus #helpful messages print("############################################################") print("Mouse to move left and right and up and down") print("############################################################") print() # Setup display and initialise pi3d DISPLAY = Display.create(x=200, y=200, frames_per_second=20) DISPLAY.set_background(0.4,0.8,0.8,1) # r,g,b,alpha camera = Camera((0, 0, 0), (0, 0, -1), (1, 1000, 30.0, DISPLAY.width/DISPLAY.height)) light = Light((10, -10, 20)) # load shader shader = Shader("shaders/uv_reflect") flatsh = Shader("shaders/uv_flat") defocus = Defocus() #======================================== # Setting 2nd param to True renders 'True' Blending # (this can be changed later to 'False' with 'rockimg2.blend = False') groundimg = Texture("textures/stripwood.jpg") monstimg = Texture("textures/pong3.png") ballimg = Texture("textures/pong2.jpg") # environment cube ectex = Texture("textures/ecubes/skybox_stormydays.jpg")
def draw(self) -> None: import numpy as np from scipy.ndimage.filters import gaussian_filter from pi3d.Camera import Camera from pi3d.constants import ( opengles, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GLsizei, GLboolean, GLint, GL_FLOAT, GL_ARRAY_BUFFER, GL_UNSIGNED_SHORT, GL_TEXTURE_2D, GL_UNSIGNED_BYTE, ) time_logging = False if self.should_prepare: self._prepare() if self.lights.alarm_program.factor != -1: self.alarm_factor = max(0.001, self.lights.alarm_program.factor) else: self.alarm_factor = 0 then = time.time() self.display.loop_running() now = self.display.time self.time_delta = now - self.last_loop self.last_loop = now self.time_elapsed += self.time_delta if time_logging: print(f"{time.time() - then} main loop") then = time.time() # use a sliding window to smooth the spectrum with a gauss function # truncating does not save significant time (~3% for this step) # new_frame = np.array(self.cava.current_frame, dtype="float32") new_frame = gaussian_filter(self.cava.current_frame, sigma=1.5, mode="nearest") new_frame = new_frame[self.SPECTRUM_CUT : -self.SPECTRUM_CUT] new_frame = -0.5 * new_frame ** 3 + 1.5 * new_frame new_frame *= 255 current_frame = new_frame if time_logging: print(f"{time.time() - then} spectrum smoothing") then = time.time() # Value used for circle shake and background color cycle # select the first few values and compute their average bass_elements = math.ceil(self.BASS_MAX * self.cava.bars) self.bass_value = sum(current_frame[0:bass_elements]) / bass_elements / 255 self.bass_value = max(self.bass_value, self.alarm_factor) self.total_bass = self.total_bass + self.bass_value # the fraction of time that there was bass self.bass_fraction = self.total_bass / self.time_elapsed / self.lights.UPS self.uniform_values = { 48: self.width / self.scale, 49: self.height / self.scale, 50: self.scale, 51: self.FFT_HIST, 52: self.NUM_PARTICLES, 53: self.PARTICLE_SPAWN_Z, 54: self.time_elapsed, 55: self.time_delta, 56: self.alarm_factor, 57: self.bass_value, 58: self.total_bass, 59: self.bass_fraction, } # start rendering to the smaller OffscreenTexture # we decrease the size of the texture so it only allocates that much memory # otherwise it would use as much as the displays size, negating its positive effect self.post.ix = int(self.post.ix / self.scale) self.post.iy = int(self.post.iy / self.scale) opengles.glViewport( GLint(0), GLint(0), GLsizei(int(self.width / self.scale)), GLsizei(int(self.height / self.scale)), ) self.post._start() self.post.ix = self.width self.post.iy = self.height self._set_unif(self.background, [48, 49, 54, 56, 58]) self.background.draw() if time_logging: print(f"{time.time() - then} background draw") then = time.time() # enable additive blending so the draw order of overlapping particles does not matter opengles.glBlendFunc(1, 1) self._set_unif(self.particle_sprite, [53, 54, 59]) # copied code from pi3d.Shape.draw() # we don't need modelmatrices, normals ord textures and always blend self.particle_sprite.load_opengl() camera = Camera.instance() if not camera.mtrx_made: camera.make_mtrx() self.particle_sprite.MRaw = self.particle_sprite.tr1 self.particle_sprite.M[0, :, :] = self.particle_sprite.MRaw[:, :] self.particle_sprite.M[1, :, :] = np.dot( self.particle_sprite.MRaw, camera.mtrx )[:, :] # Buffer.draw() buf = self.particle_sprite.buf[0] buf.load_opengl() shader = buf.shader shader.use() opengles.glUniformMatrix4fv( shader.unif_modelviewmatrix, GLsizei(2), GLboolean(0), self.particle_sprite.M.ctypes.data, ) opengles.glUniform3fv(shader.unif_unif, GLsizei(20), self.particle_sprite.unif) buf._select() opengles.glVertexAttribPointer( shader.attr_vertex, GLint(3), GL_FLOAT, GLboolean(0), buf.N_BYTES, 0 ) opengles.glEnableVertexAttribArray(shader.attr_vertex) opengles.glVertexAttribPointer( shader.attr_texcoord, GLint(2), GL_FLOAT, GLboolean(0), buf.N_BYTES, 24 ) opengles.glEnableVertexAttribArray(shader.attr_texcoord) buf.disp.last_shader = shader opengles.glUniform3fv(shader.unif_unib, GLsizei(5), buf.unib) opengles.glBindBuffer(GL_ARRAY_BUFFER, self.instance_vbo) opengles.glDrawElementsInstanced( buf.draw_method, GLsizei(buf.ntris * 3), GL_UNSIGNED_SHORT, 0, self.NUM_PARTICLES, ) # restore normal blending opengles.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) if time_logging: print(f"{time.time() - then} particle draw") then = time.time() # roll the history one further, insert the current one. # we use a texture with four channels eventhough we only need one, refer to this post: # https://community.khronos.org/t/updating-textures-per-frame/75020/3 # basically the gpu converts it anyway, so other formats would be slower history = np.zeros( (self.FFT_HIST, self.cava.bars - 2 * self.SPECTRUM_CUT, 4), dtype="uint8" ) self.fft = np.roll(self.fft, 1, 0) self.fft[0] = current_frame history[:, :, 0] = self.fft if time_logging: print(f"{time.time() - then} spectrum roll") then = time.time() # change the spectrum part of the texture (the lower 256xFFT_HIST pixels) opengles.glBindTexture(GL_TEXTURE_2D, self.dynamic_texture._tex) iformat = self.dynamic_texture._get_format_from_array( history, self.dynamic_texture.i_format ) opengles.glTexSubImage2D( GL_TEXTURE_2D, 0, 0, self.dynamic_texture.ix, history.shape[1], history.shape[0], iformat, GL_UNSIGNED_BYTE, history.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte)), ) if time_logging: print(f"{time.time() - then} glTexImage2D") then = time.time() self._set_unif(self.spectrum, [48, 49, 51, 52, 53, 54, 55, 57, 58]) self.spectrum.draw() if time_logging: print(f"{time.time() - then} spectrum draw") then = time.time() self._set_unif(self.logo, [48, 49, 51, 54, 57, 58]) self.logo.draw() if time_logging: print(f"{time.time() - then} logo draw") then = time.time() self._set_unif(self.after, [48, 49, 54, 57]) self.after.draw() if time_logging: print(f"{time.time() - then} after draw") then = time.time() self.post._end() opengles.glViewport( GLint(0), GLint(0), GLsizei(self.width), GLsizei(self.height) ) self._set_unif(self.post_sprite, [50]) self.post_sprite.draw() if time_logging: print(f"{time.time() - then} post draw") print(f"scale: {self.scale}") print("=====")
class ShadowCaster(Texture): """For creating a depth-of-field blurring effect on selected objects""" def __init__(self, emap, light): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer """ super(ShadowCaster, self).__init__("shadow_caster") from pi3d.Display import Display self.ix, self.iy = Display.INSTANCE.width, Display.INSTANCE.height self.im = Image.new("RGBA",(self.ix, self.iy)) self.image = self.im.convert("RGBA").tostring('raw', "RGBA") self.alpha = True self.blend = False self._tex = ctypes.c_int() self.framebuffer = (ctypes.c_int * 1)() opengles.glGenFramebuffers(1, self.framebuffer) self.depthbuffer = (ctypes.c_int * 1)() opengles.glGenRenderbuffers(1, self.depthbuffer) # load shader for casting shadows and camera self.cshader = Shader("shaders/uv_flat") self.mshader = Shader("shaders/mat_flat") # keep copy of ElevationMap self.emap = emap self.emap.set_material((0.0, 0.0, 0.0)) # hide bits below ground #TODO doesn't cope with z light positions self.eye = [-500*i for i in light.lightpos] # good distance away if self.eye[1] <= 0: # must have +ve y self.eye[1] = 500.0 if abs(self.eye[0]) > abs(self.eye[2]): #x val is bigger than z val #change scale so map just fits on screen if self.eye[0] < 0: su, sv = 1.0, 1.0 else: su, sv = -1.0, -1.0 self.scaleu = float(self.iy) / self.emap.width self.scalev = float(self.ix)/ self.emap.depth self.eye[2] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[0]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 1.0 #orientation flag self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[0] / float(self.eye[1]) #height adjustment else: #change scale so map just fits on screen if self.eye[2] < 0: su, sv = 1.0, -1.0 else: su, sv = -1.0, 1.0 self.scaleu = float(self.iy) / self.emap.depth self.scalev = float(self.ix)/ self.emap.width self.eye[0] = 0 self.scaleu = self.scaleu / self.eye[1] * float(self.eye[2]**2 + self.eye[1]**2)**0.5 self.emap.unif[50] = 0.0 self.emap.unif[53] = -3.0 * su / self.emap.width * self.eye[2] / float(self.eye[1]) if abs(self.scaleu) > abs(self.scalev): self.scale = 3.0 * self.scalev # multiplication factor to reduce pixeliness else: self.scale = 3.0 * self.scaleu self.scaleu = su * self.scale / self.scaleu # reused later in end_cast self.scalev = sv * self.scale / self.scalev self.camera0 = Camera() # default instance created as normal, just in case! self.camera = Camera(is_3d=False, eye=self.eye, scale=self.scale) # load shader for drawing map with shadows self.dshader = Shader("shaders/shadowcast") def _load_disk(self): """ have to override this """ def start_cast(self, location=(0.0, 0.0, 0.0)): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. If you want blurred edges you will have to capture the rendering of an object and its background then re-draw them using the blur() method. Large objects will obviously take a while to draw and re-draw """ opengles.glBindFramebuffer(GL_FRAMEBUFFER, self.framebuffer) opengles.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self._tex.value, 0) #thanks to PeterO c.o. RPi forum for pointing out missing depth attchmnt opengles.glBindRenderbuffer(GL_RENDERBUFFER, self.depthbuffer) opengles.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.ix, self.iy) opengles.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, self.depthbuffer) opengles.glClearColor(ctypes.c_float(0.0), ctypes.c_float(0.0), ctypes.c_float(0.0), ctypes.c_float(1.0)) opengles.glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) opengles.glEnable(GL_TEXTURE_2D) opengles.glActiveTexture(0) self.camera.reset(is_3d=False, scale=self.scale) self.camera.position((location[0], 0, location[2])) self.location = location def end_cast(self): """ stop capturing to texture and resume normal rendering to default """ #draw the actual map self.emap.draw(shader=self.mshader, camera=self.camera) opengles.glBindTexture(GL_TEXTURE_2D, 0) opengles.glBindFramebuffer(GL_FRAMEBUFFER, 0) # set third texture to this ShadowCaster texture texs = self.emap.buf[0].textures if len(texs) == 2: texs.append(self) else: texs[2] = self # change background back to blue opengles.glClearColor(ctypes.c_float(0.4), ctypes.c_float(0.8), ctypes.c_float(0.8), ctypes.c_float(1.0)) # work out left, top, right, bottom for shader self.emap.unif[48] = 0.5 * (1.0 + self.scaleu) # left [16][0] self.emap.unif[49] = 0.5 * (1.0 + self.scalev) # top [16][1] self.emap.unif[51] = 1.0 - self.emap.unif[48] # right [17][0] self.emap.unif[52] = 1.0 - self.emap.unif[49] # bottom [17][1] du = float(self.location[0] / self.emap.width) dv = float(self.location[2] / self.emap.depth) self.emap.unif[48] -= self.scaleu * (du if self.emap.unif[50] == 1.0 else dv) self.emap.unif[49] += self.scalev * (dv if self.emap.unif[50] == 1.0 else du) self.emap.unif[51] -= self.scaleu * (du if self.emap.unif[50] == 1.0 else dv) self.emap.unif[52] += self.scalev * (dv if self.emap.unif[50] == 1.0 else du) def add_shadow(self, shape): shape.draw(shader=self.cshader, camera=self.camera) def draw_shadow(self): self.emap.draw(shader=self.dshader) def delete_buffers(self): opengles.glDeleteFramebuffers(1, self.framebuffer) opengles.glDeleteRenderbuffers(1, self.depthbuffer)
from pi3d.Light import Light from pi3d.Shader import Shader from pi3d.util.String import String from pi3d.util.Ttffont import Ttffont from pi3d.util.Defocus import Defocus from pi3d.util.Screenshot import screenshot from pi3d.shape.MergeShape import MergeShape from pi3d.shape.Sphere import Sphere from pi3d.shape.Sprite import Sprite # Setup display and initialise pi3d DISPLAY = Display.create(x=10, y=10, w=900, h=600, frames_per_second=25) DISPLAY.set_background(0.4, 0.6, 0.8, 1.0) # r,g,b,alpha persp_cam = Camera.instance() # default instance camera perspecive view ortho_cam = Camera(is_3d=False) # 2d orthographic view camera #setup textures, light position and initial model position Light((0, 5, 0)) #create shaders shader = Shader("shaders/uv_reflect") flatsh = Shader("shaders/uv_flat") defocus = Defocus() #Create textures shapeimg = Texture("textures/straw1.jpg") shapebump = Texture("textures/floor_nm.jpg", True) shapeshine = Texture("textures/pong3.png") #Create shape
tank_turret.rotateToZ(roll) tank_turret.draw() tank_gun.position(x, y, z) # adjust gunangle for tilted plane as turret rotates tank_gun.rotateToX(pitch + math.cos(math.radians(turret - 180)) * gunangle) tank_gun.rotateToY(turret-90) tank_gun.rotateToZ(roll - math.sin(math.radians(turret - 180)) * gunangle) tank_gun.draw() # Update display before we begin (user might have moved window) win.update() DISPLAY.resize(win.winx, win.winy, win.width, win.height - bord) is_running = True CAMERA = Camera.instance() try: while DISPLAY.loop_running(): mx, my = mymouse.position() mouserot -= (mx-omx)*0.2 tilt += (my-omy)*0.2 omx=mx omy=my CAMERA.reset() dot1.set_2d_location(DISPLAY.width - 105.0 + 200.0*xm/mapwidth, DISPLAY.height - 105.0 - 200.0*zm/mapdepth) dot2.set_2d_location(DISPLAY.width - 105.0 + 200.0*etx/mapwidth, DISPLAY.height - 105.0 - 200.0*etz/mapdepth) dot1.draw()
class StereoCam(object): """For creating an apparatus with two sprites to hold left and right eye views. This Class is used to hold the 3D Camera which should be used to draw the 3D objects. It also holds a 2D Camera for drawing the Sprites""" def __init__(self, shader="uv_flat", mipmap=False, separation=0.4): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to post_base, a simple 3x3 convolution that does basic edge detection. Can be copied to project directory and modified as required. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. """ # load shader self.shader = Shader(shader) self.camera_3d = Camera() self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="bin")) ix, iy = self.textures[i].ix, self.textures[i].iy #two sprites full width but moved so that they are centred on the #left and right edges. The offset values then move the uv mapping #so the image is on the right of the left sprite and left of the #right sprite self.sprites.append(Sprite(z=20.0, x=-ix/2.0 + i*ix, w=ix, h=iy, flip=True)) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) self.textures[i].alpha = False self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append([self.textures[i]]) def move_camera(self, position, rot, tilt): self.camera_3d.reset() self.camera_3d.rotate(tilt, rot, 0) self.camera_3d.position(position) def start_capture(self, side): """ after calling this method all object.draw()s will rendered to this texture and not appear on the display. *side* Either 0 or 1 to determine stereoscopic view """ offs = -self.offs if side == 0 else self.offs self.camera_3d.position((self.camera_3d.mtrx[2,3] * offs, 0, -self.camera_3d.mtrx[0,3] * offs)) tex = self.textures[side] tex._start() xx = tex.ix / 4.0 # draw the middle only - half width yy = 0 ww = tex.ix / 2.0 hh = tex.iy opengles.glEnable(GL_SCISSOR_TEST) opengles.glScissor(ctypes.c_int(int(xx)), ctypes.c_int(int(yy)), ctypes.c_int(int(ww)), ctypes.c_int(int(hh))) def end_capture(self, side): """ stop capturing to texture and resume normal rendering to default """ self.textures[side]._end() opengles.glDisable(GL_SCISSOR_TEST) def draw(self): """ draw the shape using the saved texture """ for i in range(2): self.sprites[i].draw(self.shader, self.tex_list[i], 0.0, 0.0, self.camera_2d)
from pi3d.shape.Sphere import Sphere from pi3d.util.String import String from pi3d.util.Screenshot import screenshot from pi3d.util.Defocus import Defocus #helpful messages print("############################################################") print("Mouse to move left and right and up and down") print("############################################################") print() # Setup display and initialise pi3d DISPLAY = Display.create(x=200, y=200, frames_per_second=20) DISPLAY.set_background(0.4, 0.8, 0.8, 1) # r,g,b,alpha camera = Camera((0, 0, 0), (0, 0, -1), (1, 1000, 30.0, DISPLAY.width / DISPLAY.height)) light = Light((10, -10, 20)) # load shader shader = Shader("shaders/uv_reflect") flatsh = Shader("shaders/uv_flat") defocus = Defocus() #======================================== # Setting 2nd param to True renders 'True' Blending # (this can be changed later to 'False' with 'rockimg2.blend = False') groundimg = Texture("textures/stripwood.jpg") monstimg = Texture("textures/pong3.png") ballimg = Texture("textures/pong2.jpg") # environment cube ectex = Texture("textures/ecubes/skybox_stormydays.jpg")
def __init__(self, shader="uv_flat", mipmap=False, separation=0.4, interlace=0): """ calls Texture.__init__ but doesn't need to set file name as texture generated from the framebuffer. Keyword Arguments: *shader* to use when drawing sprite, defaults to uv_flat. *mipmap* can be set to True with slight cost to speed, or use fxaa shader *separation* distance between the two camera positions - how wide apart the eye views are. *interlace* if interlace > 0 then the images are not taken with glScissor and must be drawn with a special interlacing shader. """ # load shader if interlace <= 0: # i.e. default side by side behaviour self.shader = Shader.create(shader) else: self.shader = Shader(vshader_source = """ precision mediump float; attribute vec3 vertex; attribute vec2 texcoord; uniform mat4 modelviewmatrix[2]; varying vec2 texcoordout; void main(void) { texcoordout = texcoord; gl_Position = modelviewmatrix[1] * vec4(vertex,1.0); } """, fshader_source = """ precision mediump float; uniform sampler2D tex0; uniform sampler2D tex1; varying vec2 texcoordout; void main(void) {{ vec4 texc0 = texture2D(tex0, texcoordout); vec4 texc1 = texture2D(tex1, texcoordout); vec2 coord = vec2(gl_FragCoord); gl_FragColor = mix(texc0, texc1, step(0.5, fract(coord.x / {:f}))); }} """.format(interlace * 2.0)) self.camera_3d = Camera() # create 3d cam first so it becomes default instance self.forMtrx = np.identity(4, dtype='float32') # initially not rotated self.position = [0.0, 0.0, 0.0] self.camera_2d = Camera(is_3d=False) self.offs = separation / 2.0 self.interlace = interlace self.textures = [] self.sprites = [] self.tex_list = [] for i in range(2): self.textures.append(OffScreenTexture(name="stereo")) ix, iy = self.textures[i].ix, self.textures[i].iy #two sprites full width but moved so that they are centred on the #left and right edges. The offset values then move the uv mapping #so the image is on the right of the left sprite and left of the #right sprite self.sprites.append(Sprite(z=20.0, w=ix, h=iy, flip=True)) if interlace <= 0: self.sprites[i].positionX(-ix/2.0 + i*ix) self.sprites[i].set_offset((i * 0.5 - 0.25, 0.0)) else: self.sprites[i].set_2d_size(w=ix, h=iy) self.textures[i].blend = True self.textures[i].mipmap = mipmap self.tex_list.append(self.textures[i]) opengles.glColorMask(1, 1, 1, 1)