def _late_init(self, task): """ Gets called after the pipeline was initialized """ self._display_txt = Text( text="40 ms", parent=self._node, x=20, y=25, size=13, color=Vec3(1), may_change=True) self._display_txt_bottom = Text( text="0 ms", parent=self._node, x=20, y=120, size=13, color=Vec3(1), may_change=True) # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("FPSChartUpdateChart") self._cshader_node.add_dispatch(250 // 10, 120 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) self._cshader = RPLoader.load_shader("/$$rp/shader/fps_chart.compute.glsl") self._cshader_np.set_shader(self._cshader) self._cshader_np.set_shader_input("DestTex", self._display_tex) self._cshader_np.set_shader_input("FPSValues", self._storage_buffer) self._cshader_np.set_shader_input("index", self._store_index) self._cshader_np.set_shader_input("maxMs", self._chart_ms_max) self._update_shader_node = ComputeNode("FPSChartUpdateValues") self._update_shader_node.add_dispatch(1, 1, 1) self._update_shader_np = self._node.attach_new_node(self._update_shader_node) self._ushader = RPLoader.load_shader("/$$rp/shader/fps_chart_update.compute.glsl") self._update_shader_np.set_shader(self._ushader) self._update_shader_np.set_shader_input("DestTex", self._storage_buffer) self._update_shader_np.set_shader_input("index", self._store_index) self._update_shader_np.set_shader_input("currentData", self._current_ftime) Globals.base.addTask(self._update, "UpdateFPSChart", sort=-50) return task.done
class ExposureWidget(DebugObject): """ Widget to show the current exposure """ def __init__(self, pipeline, parent): """ Inits the widget """ DebugObject.__init__(self) self._pipeline = pipeline self._parent = parent self._node = self._parent.attach_new_node("ExposureWidgetNode") self._create_components() def _create_components(self): """ Internal method to init the widgets components """ self._node.hide() # Create the texture where the gui component is rendered inside self._storage_tex = Image.create_2d("ExposureDisplay", 140, 20, Texture.T_unsigned_byte, Texture.F_rgba8) self._storage_tex.set_clear_color(Vec4(0.2, 0.6, 1.0, 1.0)) self._storage_tex.clear_image() self._bg_frame = DirectFrame(parent=self._node, frameColor=(0.1, 0.1, 0.1, 1.0), frameSize=(200, 0, -10, -85), pos=(0, 0, 0)) self._display_img = BetterOnscreenImage( image=self._storage_tex, parent=self._node, w=140, h=20, x=20, y=50) self._display_txt = BetterOnscreenText( text="Current Exposure".upper(), parent=self._node, x=160, y=40, size=13, color=Vec3(0.8), align="right") # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("ExposureWidget") self._cshader_node.add_dispatch(140 // 10, 20 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) # Defer the further loading Globals.base.taskMgr.doMethodLater(1.0, self._late_init, "ExposureLateInit") def _late_init(self, task): """ Gets called after the pipeline initialized, this extracts the exposure texture from the stage manager """ stage_mgr = self._pipeline.stage_mgr if not stage_mgr.has_pipe("Exposure"): self.debug("Disabling exposure widget, could not find the exposure data.") self._node.remove_node() return self._node.show() exposure_tex = stage_mgr.get_pipe("Exposure") self._cshader = Shader.load_compute(Shader.SL_GLSL, "Shader/GUI/VisualizeExposure.compute.glsl") self._cshader_np.set_shader(self._cshader) self._cshader_np.set_shader_input("DestTex", self._storage_tex) self._cshader_np.set_shader_input("ExposureTex", exposure_tex)
def _create_components(self): """ Internal method to init the widgets components """ self._node.hide() # Create the texture where the gui component is rendered inside self._storage_tex = Image.create_2d("ExposureDisplay", 140, 20, "RGBA8") self._storage_tex.set_clear_color(Vec4(0.2, 0.6, 1.0, 1.0)) self._storage_tex.clear_image() self._bg_frame = DirectFrame( parent=self._node, frameColor=(0.1, 0.1, 0.1, 1.0), frameSize=(200, 0, -10, -85), pos=(0, 0, 0)) self._display_img = Sprite( image=self._storage_tex, parent=self._node, w=140, h=20, x=20, y=50) self._display_txt = Text( text="Current Exposure".upper(), parent=self._node, x=160, y=40, size=13, color=Vec3(0.8), align="right") # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("ExposureWidget") self._cshader_node.add_dispatch(140 // 10, 20 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) # Defer the further loading Globals.base.taskMgr.doMethodLater(1.0, self._late_init, "ExposureLateInit")
def _late_init(self, task): """ Gets called after the pipeline was initialized """ self._display_txt = Text(text="40 ms", parent=self._node, x=20, y=25, size=13, color=Vec3(1), may_change=True) self._display_txt_bottom = Text(text="0 ms", parent=self._node, x=20, y=120, size=13, color=Vec3(1), may_change=True) # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("FPSChartUpdateChart") self._cshader_node.add_dispatch(250 // 10, 120 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) self._cshader = RPLoader.load_shader( "/$$rp/shader/fps_chart.compute.glsl") self._cshader_np.set_shader(self._cshader) self._cshader_np.set_shader_input("DestTex", self._display_tex) self._cshader_np.set_shader_input("FPSValues", self._storage_buffer) self._cshader_np.set_shader_input("index", self._store_index) self._cshader_np.set_shader_input("maxMs", self._chart_ms_max) self._update_shader_node = ComputeNode("FPSChartUpdateValues") self._update_shader_node.add_dispatch(1, 1, 1) self._update_shader_np = self._node.attach_new_node( self._update_shader_node) self._ushader = RPLoader.load_shader( "/$$rp/shader/fps_chart_update.compute.glsl") self._update_shader_np.set_shader(self._ushader) self._update_shader_np.set_shader_input("DestTex", self._storage_buffer) self._update_shader_np.set_shader_input("index", self._store_index) self._update_shader_np.set_shader_input("currentData", self._current_ftime) Globals.base.addTask(self._update, "UpdateFPSChart", sort=-50) return task.done
def enable(self): if not self.isSupported(): # HDR/auto exposure is implemented using compute # shaders, which are only supported by more modern # graphics cards and requires at least OpenGL 4.3. return self.sceneTex = Texture('hdrSceneTex') self.sceneTex.setup2dTexture(self.Size, self.Size, Texture.TFloat, Texture.FRgba32) self.sceneTex.setWrapU(SamplerState.WMClamp) self.sceneTex.setWrapV(SamplerState.WMClamp) self.sceneTex.clearImage() self.__setupSceneQuad() # Build luminance histogram bucket ranges. self.ptaBucketRange = PTALVecBase2f.emptyArray(self.NumBuckets) for i in xrange(self.NumBuckets): # Use even distribution bmin = float(i) / float(self.NumBuckets) bmax = float(i + 1) / float(self.NumBuckets) # Use a distribution with slightly more bins in the low range. if bmin > 0.0: bmin = math.pow(bmin, 1.5) if bmax > 0.0: bmax = math.pow(bmax, 1.5) self.ptaBucketRange.setElement(i, Vec2(bmin, bmax)) self.histogramTex = Texture('histogram') self.histogramTex.setup1dTexture(self.NumBuckets, Texture.TInt, Texture.FR32i) self.histogramTex.setClearColor(Vec4(0)) self.histogramTex.clearImage() self.histogramCompute = base.computeRoot.attachNewNode(ComputeNode('histogramCompute')) self.histogramCompute.node().addDispatch(self.Size / 8, self.Size / 8, self.Size / 16) self.histogramCompute.setShader(Shader.loadCompute(Shader.SLGLSL, "phase_14/models/shaders/build_histogram.compute.glsl"), 1) self.histogramCompute.setShaderInput("scene_texture", self.sceneTex) self.histogramCompute.setShaderInput("histogram_texture", self.histogramTex) self.histogramCompute.setShaderInput("bucketrange", self.ptaBucketRange) self.histogramCompute.setBin("fixed", 0) self.exposureTex = Texture('exposure') self.exposureTex.setup1dTexture(1, Texture.TFloat, Texture.FR16) self.exposureTex.setClearColor(Vec4(0.0)) self.exposureTex.clearImage() self.exposureCompute = base.computeRoot.attachNewNode(ComputeNode('exposureCompute')) self.exposureCompute.node().addDispatch(1, 1, 1) self.exposureCompute.setShader(Shader.loadCompute(Shader.SLGLSL, "phase_14/models/shaders/calc_luminance.compute.glsl"), 1) self.exposureCompute.setShaderInput("histogram_texture", self.histogramTex) self.exposureCompute.setShaderInput("avg_lum_texture", self.exposureTex) self.exposureCompute.setShaderInput("bucketrange", self.ptaBucketRange) self.exposureCompute.setShaderInput("exposure_minmax", Vec2(1.0, 2.0)) self.exposureCompute.setShaderInput("adaption_rate_brightdark", Vec2(0.6, 0.6)) self.exposureCompute.setShaderInput("exposure_scale", base.config.GetFloat("hdr-tonemapscale", 1.75)) self.exposureCompute.setShaderInput("config_minAvgLum", base.config.GetFloat("hdr-min-avglum", 3.0)) self.exposureCompute.setShaderInput("config_perctBrightPixels", base.config.GetFloat("hdr-percent-bright-pixels", 2.0)) self.exposureCompute.setShaderInput("config_perctTarget", base.config.GetFloat("hdr-percent-target", 60.0)) self.exposureCompute.setBin("fixed", 1) base.filters.setExposure(self.exposureTex) taskMgr.add(self.__update, "hdrUpdate", sort = -10000000) if base.config.GetBool("hdr-debug-histogram", False): self.debugTex = Texture('histogramDebugTex') self.debugTex.setup2dTexture(self.NumBuckets, 1, Texture.TFloat, Texture.FRgba32) self.debugTex.setMagfilter(SamplerState.FTNearest) self.debugTex.setClearColor(Vec4(0.3, 0.3, 0.5, 1.0)) self.debugTex.clearImage() self.debugCompute = base.computeRoot.attachNewNode(ComputeNode('debugHistogramCompute')) self.debugCompute.node().addDispatch(1, 1, 1) self.debugCompute.setShader(Shader.loadCompute(Shader.SLGLSL, "phase_14/models/shaders/debug_histogram.compute.glsl"), 1) self.debugCompute.setShaderInput("histogram_texture", self.histogramTex) self.debugCompute.setShaderInput("debug_texture", self.debugTex) self.debugCompute.setBin("fixed", 2) self.debugImg = OnscreenImage(image = self.debugTex, scale = 0.3, pos = (-0.6, -0.7, -0.7))
class FPSChart(RPObject): """ Widget to show the FPS as a chart """ def __init__(self, pipeline, parent): """ Inits the widget """ RPObject.__init__(self) self._pipeline = pipeline self._parent = parent self._node = self._parent.attach_new_node("FPSChartNode") self._create_components() def _create_components(self): """ Internal method to init the widgets components """ # Create the buffer which stores the last FPS values self._storage_buffer = Image.create_buffer("FPSValues", 250, "R16") self._storage_buffer.set_clear_color(Vec4(0)) self._storage_buffer.clear_image() self._store_index = PTAInt.empty_array(1) self._store_index[0] = 0 self._current_ftime = PTAFloat.empty_array(1) self._current_ftime[0] = 16.0 self._chart_ms_max = PTAFloat.empty_array(1) self._chart_ms_max[0] = 40 # Create the texture where the gui component is rendered inside self._display_tex = Image.create_2d("FPSChartRender", 250, 120, "RGBA8") self._display_tex.set_clear_color(Vec4(0)) self._display_tex.clear_image() self._display_img = Sprite(image=self._display_tex, parent=self._node, w=250, h=120, x=10, y=10) # Defer the further loading Globals.base.taskMgr.doMethodLater(0.3, self._late_init, "FPSChartInit") def _late_init(self, task): """ Gets called after the pipeline was initialized """ self._display_txt = Text(text="40 ms", parent=self._node, x=20, y=25, size=13, color=Vec3(1), may_change=True) self._display_txt_bottom = Text(text="0 ms", parent=self._node, x=20, y=120, size=13, color=Vec3(1), may_change=True) # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("FPSChartUpdateChart") self._cshader_node.add_dispatch(250 // 10, 120 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) self._cshader = RPLoader.load_shader( "/$$rp/shader/fps_chart.compute.glsl") self._cshader_np.set_shader(self._cshader) self._cshader_np.set_shader_inputs(DestTex=self._display_tex, FPSValues=self._storage_buffer, index=self._store_index, maxMs=self._chart_ms_max) self._update_shader_node = ComputeNode("FPSChartUpdateValues") self._update_shader_node.add_dispatch(1, 1, 1) self._update_shader_np = self._node.attach_new_node( self._update_shader_node) self._ushader = RPLoader.load_shader( "/$$rp/shader/fps_chart_update.compute.glsl") self._update_shader_np.set_shader(self._ushader) self._update_shader_np.set_shader_inputs( DestTex=self._storage_buffer, index=self._store_index, currentData=self._current_ftime) Globals.base.addTask(self._update, "UpdateFPSChart", sort=-50) return task.done def _update(self, task): """ Updates the widget """ self._store_index[0] = (self._store_index[0] + 1) % 250 self._current_ftime[0] = Globals.clock.get_dt() * 1000.0 avg_fps = Globals.clock.get_average_frame_rate() if avg_fps > 122: self._chart_ms_max[0] = 10.0 elif avg_fps > 62: self._chart_ms_max[0] = 20.0 elif avg_fps > 32: self._chart_ms_max[0] = 40.0 elif avg_fps > 15: self._chart_ms_max[0] = 70.0 else: self._chart_ms_max[0] = 200.0 self._display_txt.set_text(str(int(self._chart_ms_max[0])) + " ms") return task.cont
class ExposureWidget(RPObject): """ Widget to show the current exposure """ def __init__(self, pipeline, parent): """ Inits the widget """ RPObject.__init__(self) self._pipeline = pipeline self._parent = parent self._node = self._parent.attach_new_node("ExposureWidgetNode") self._create_components() def _create_components(self): """ Internal method to init the widgets components """ self._node.hide() # Create the texture where the gui component is rendered inside self._storage_tex = Image.create_2d("ExposureDisplay", 140, 20, "RGBA8") self._storage_tex.set_clear_color(Vec4(0.2, 0.6, 1.0, 1.0)) self._storage_tex.clear_image() self._bg_frame = DirectFrame(parent=self._node, frameColor=(0.1, 0.1, 0.1, 1.0), frameSize=(200, 0, -10, -85), pos=(0, 0, 0)) self._display_img = Sprite(image=self._storage_tex, parent=self._node, w=140, h=20, x=20, y=50) self._display_txt = Text(text="Current Exposure".upper(), parent=self._node, x=160, y=40, size=13, color=Vec3(0.8), align="right") # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("ExposureWidget") self._cshader_node.add_dispatch(140 // 10, 20 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) # Defer the further loading Globals.base.taskMgr.doMethodLater(1.0, self._late_init, "ExposureLateInit") def _late_init(self, task): """ Gets called after the pipeline initialized, this extracts the exposure texture from the stage manager """ stage_mgr = self._pipeline.stage_mgr if "Exposure" not in stage_mgr.pipes: self.debug( "Disabling exposure widget, could not find the exposure data.") self._node.remove_node() return self._node.show() exposure_tex = stage_mgr.pipes["Exposure"] self._cshader = RPLoader.load_shader( "/$$rp/shader/visualize_exposure.compute.glsl") self._cshader_np.set_shader(self._cshader) self._cshader_np.set_shader_input("DestTex", self._storage_tex) self._cshader_np.set_shader_input("ExposureTex", exposure_tex) return task.done
class FPSChart(RPObject): """ Widget to show the FPS as a chart """ def __init__(self, pipeline, parent): """ Inits the widget """ RPObject.__init__(self) self._pipeline = pipeline self._parent = parent self._node = self._parent.attach_new_node("FPSChartNode") self._create_components() def _create_components(self): """ Internal method to init the widgets components """ # Create the buffer which stores the last FPS values self._storage_buffer = Image.create_buffer("FPSValues", 250, "R16") self._storage_buffer.set_clear_color(Vec4(0)) self._storage_buffer.clear_image() self._store_index = PTAInt.empty_array(1) self._store_index[0] = 0 self._current_ftime = PTAFloat.empty_array(1) self._current_ftime[0] = 16.0 self._chart_ms_max = PTAFloat.empty_array(1) self._chart_ms_max[0] = 40 # Create the texture where the gui component is rendered inside self._display_tex = Image.create_2d("FPSChartRender", 250, 120, "RGBA8") self._display_tex.set_clear_color(Vec4(0)) self._display_tex.clear_image() self._display_img = Sprite( image=self._display_tex, parent=self._node, w=250, h=120, x=10, y=10) # Defer the further loading Globals.base.taskMgr.doMethodLater(0.3, self._late_init, "FPSChartInit") def _late_init(self, task): """ Gets called after the pipeline was initialized """ self._display_txt = Text( text="40 ms", parent=self._node, x=20, y=25, size=13, color=Vec3(1), may_change=True) self._display_txt_bottom = Text( text="0 ms", parent=self._node, x=20, y=120, size=13, color=Vec3(1), may_change=True) # Create the shader which generates the visualization texture self._cshader_node = ComputeNode("FPSChartUpdateChart") self._cshader_node.add_dispatch(250 // 10, 120 // 4, 1) self._cshader_np = self._node.attach_new_node(self._cshader_node) self._cshader = RPLoader.load_shader("/$$rp/shader/fps_chart.compute.glsl") self._cshader_np.set_shader(self._cshader) self._cshader_np.set_shader_input("DestTex", self._display_tex) self._cshader_np.set_shader_input("FPSValues", self._storage_buffer) self._cshader_np.set_shader_input("index", self._store_index) self._cshader_np.set_shader_input("maxMs", self._chart_ms_max) self._update_shader_node = ComputeNode("FPSChartUpdateValues") self._update_shader_node.add_dispatch(1, 1, 1) self._update_shader_np = self._node.attach_new_node(self._update_shader_node) self._ushader = RPLoader.load_shader("/$$rp/shader/fps_chart_update.compute.glsl") self._update_shader_np.set_shader(self._ushader) self._update_shader_np.set_shader_input("DestTex", self._storage_buffer) self._update_shader_np.set_shader_input("index", self._store_index) self._update_shader_np.set_shader_input("currentData", self._current_ftime) Globals.base.addTask(self._update, "UpdateFPSChart", sort=-50) return task.done def _update(self, task): """ Updates the widget """ self._store_index[0] = (self._store_index[0] + 1) % 250 self._current_ftime[0] = Globals.clock.get_dt() * 1000.0 avg_fps = Globals.clock.get_average_frame_rate() if avg_fps > 122: self._chart_ms_max[0] = 10.0 elif avg_fps > 62: self._chart_ms_max[0] = 20.0 elif avg_fps > 32: self._chart_ms_max[0] = 40.0 elif avg_fps > 15: self._chart_ms_max[0] = 70.0 else: self._chart_ms_max[0] = 200.0 self._display_txt.set_text(str(int(self._chart_ms_max[0])) + " ms") return task.cont