@@ -111,7 +111,8 @@ def __init__(self, wisp_state, window_name="wisp app"):
111111 # There we generate a simple billboard GL program (normally with a shared CUDA resource)
112112 # Canvas content will be blitted onto it
113113 self .canvas_program : Optional [gloo .Program ] = None # GL program used to paint a single billboard
114- self .cugl_rgb_handle = None # CUDA buffer, as a shared resource with OpenGL
114+ self .vao : Optional [gloo .VertexArray ] = None # Vertex array object to hold GL buffers
115+ self .cugl_rgb_handle = None # CUDA buffer, as a shared resource with OpenGL
115116 self .cugl_depth_handle = None
116117
117118 try :
@@ -133,7 +134,7 @@ def __init__(self, wisp_state, window_name="wisp app"):
133134 self .change_user_mode (self .default_user_mode ())
134135
135136 self .redraw () # Refresh RendererCore
136-
137+
137138 def add_pipeline (self , name , pipeline , transform = None ):
138139 """Register a neural fields pipeline into the scene graph.
139140
@@ -143,7 +144,7 @@ def add_pipeline(self, name, pipeline, transform=None):
143144 transform (wisp.core.ObjectTransform): The transform for the pipeline.
144145 """
145146 add_pipeline_to_scene_graph (self .wisp_state , name , pipeline , transform = transform )
146-
147+
147148 def add_widget (self , widget ):
148149 """ Adds a widget to the list of widgets.
149150
@@ -242,10 +243,10 @@ def run(self):
242243 """
243244 app .run () # App clock should always run as frequently as possible (background tasks should not be limited)
244245
245- def _create_window (self , width , height , window_name , gl_version ):
246+ def _create_window (self , width , height , window_name , gl_version ) -> app . Window :
246247 # Currently assume glfw backend due to integration with imgui
247248 app .use (f"glfw_imgui ({ gl_version } )" )
248- win_config = app .configuration .Configuration ()
249+ win_config = app .configuration .get_default ()
249250 if self .wisp_state .renderer .antialiasing == 'msaa_4x' :
250251 win_config .samples = 4
251252
@@ -267,7 +268,7 @@ def _create_window(self, width, height, window_name, gl_version):
267268 return window
268269
269270 @staticmethod
270- def _create_gl_depth_billboard_program (texture : np .ndarray , depth_texture : np .ndarray ):
271+ def _create_gl_depth_billboard_program (texture : np .ndarray , depth_texture : np .ndarray ) -> gloo . Program :
271272 vertex = """
272273 uniform float scale;
273274 attribute vec2 position;
@@ -301,8 +302,22 @@ def _create_gl_depth_billboard_program(texture: np.ndarray, depth_texture: np.nd
301302 canvas ['depth_tex' ] = depth_texture
302303 return canvas
303304
305+ def _create_vao (self , gl_config : app .Configuration ) -> gloo .VertexArray :
306+ """ Creates a "default" VertexBufferObject to be used by the GL Programs. """
307+ # OpenGL 3.3+ requires that a VertexArrayObject is always bound.
308+ # Since glumpy's glfw_imgui backend doesn't guarantee one, and imgui expects a GL context with OpenGL >= 3.3,
309+ # we create a default one here for all programs and buffers which gloo will bind its buffers to.
310+ # This isn't how VAOs are meant to be used: it is more correct to keep a VAO per group of buffers (in Wisp's
311+ # case, at least once per gizmo). However, the following glumpy issue needs to be sorted out first, see:
312+ # https://github.com/glumpy/glumpy/issues/310
313+ vao = None
314+ if gl_config .major_version >= 3 :
315+ vao = np .zeros (0 , np .float32 ).view (gloo .VertexArray ) # Keep GL happy by binding with some VAO handle
316+ vao .activate () # Actual vao created here
317+ return vao
318+
304319 @staticmethod
305- def _create_screen_texture (res_h , res_w , channel_depth , dtype = np .uint8 ):
320+ def _create_screen_texture (res_h , res_w , channel_depth , dtype = np .uint8 ) -> gloo . Texture2D :
306321 """ Create and return a Texture2D with gloo and a cuda handle. """
307322 if issubclass (dtype , np .integer ):
308323 tex = np .zeros ((res_h , res_w , channel_depth ), dtype ).view (gloo .Texture2D )
@@ -385,7 +400,7 @@ def render_canvas(self, render_core, time_delta, force_render):
385400
386401 return img , depth_img
387402
388- def _blit_to_gl_renderbuffer (self , img , depth_img , canvas_program , cugl_rgb_handle , cugl_depth_handle , height ):
403+ def _blit_to_gl_renderbuffer (self , img , depth_img , canvas_program , vao , cugl_rgb_handle , cugl_depth_handle , height ):
389404 if self .blitdevice2device :
390405 # Device to device copy: Copy CUDA buffer to GL Texture mem
391406 shared_tex = canvas_program ['tex' ]
@@ -402,6 +417,8 @@ def _blit_to_gl_renderbuffer(self, img, depth_img, canvas_program, cugl_rgb_hand
402417 canvas_program ['tex' ] = img .cpu ().numpy ()
403418 canvas_program ['depth_tex' ] = depth_img .cpu ().numpy ()
404419
420+ if vao is not None :
421+ vao .activate ()
405422 canvas_program .draw (gl .GL_TRIANGLE_STRIP )
406423
407424 def update_renderer_state (self , wisp_state , dt ):
@@ -487,7 +504,7 @@ def render(self):
487504
488505 # glumpy code injected within the pyimgui render loop to blit the renderer core output to the actual canvas
489506 # The torch buffers are copied by with cuda, connected as shared resources as 2d GL textures
490- self ._blit_to_gl_renderbuffer (img , depth_img , self .canvas_program , self .cugl_rgb_handle ,
507+ self ._blit_to_gl_renderbuffer (img , depth_img , self .canvas_program , self .vao , self . cugl_rgb_handle ,
491508 self .cugl_depth_handle , self .height )
492509
493510 # Finally, render OpenGL gizmos on the canvas.
@@ -544,6 +561,7 @@ def on_resize(self, width, height):
544561 self .cugl_depth_handle = self ._register_cugl_shared_texture (depth_tex )
545562 if self .canvas_program is None :
546563 self .canvas_program = self ._create_gl_depth_billboard_program (texture = tex , depth_texture = depth_tex )
564+ self .vao = self ._create_vao (self .window .config )
547565 else :
548566 if self .canvas_program ['tex' ] is not None :
549567 self .canvas_program ['tex' ].delete ()
@@ -708,7 +726,6 @@ def dump_framebuffer(self, path='./framebuffer'):
708726 framebuffer = np .flip (framebuffer , 0 )
709727 ext .png .from_array (framebuffer , 'L' ).save (path + '_depth.png' )
710728
711-
712729 def register_io_mappings (self ):
713730 WispMouseButton .register_symbol (WispMouseButton .LEFT_BUTTON , app .window .mouse .LEFT )
714731 WispMouseButton .register_symbol (WispMouseButton .MIDDLE_BUTTON , app .window .mouse .MIDDLE )
@@ -720,4 +737,3 @@ def register_io_mappings(self):
720737 WispKey .register_symbol (WispKey .DOWN , app .window .key .DOWN )
721738
722739 # TODO: Take care of remaining mappings, and verify the event handlers of glumpy were not overriden
723-
0 commit comments