def test_shader_load_compute(vfs, ramdir): # Try non-existent first. shad0 = Shader.load_compute(Shader.SL_GLSL, "/nonexistent.glsl") assert shad0 is None comp_file = Filename(ramdir, "shader.glsl") # Now write some actual content to the shader file. vfs.write_file(comp_file, b"#version 100\nvoid main() {}\n", False) shad1 = Shader.load_compute(Shader.SL_GLSL, comp_file) assert shad1 is not None assert shad1.this # Load the same shader, it should return the cached result. shad2 = Shader.load_compute(Shader.SL_GLSL, comp_file) assert shad2 is not None assert shad1.this == shad2.this # After waiting a second to make the timestamp different, modify the # shader and load again, it should result in a different object now time.sleep(1.0) vfs.write_file(comp_file, b"#version 110\nvoid main() {}\n", False) shad2 = Shader.load_compute(Shader.SL_GLSL, comp_file) assert shad2.this != shad1.this
def __init__(self, size, source_tex, normalization_factor): """ Creates a new fft instance. The source texture has to specified from the begining, as the shaderAttributes are pregenerated for performance reasons """ self.size = size self.log2_size = int(math.log(size, 2)) self.normalization_factor = normalization_factor # Create a ping and a pong texture, because we can't write to the # same texture while reading to it (that would lead to unexpected # behaviour, we could solve that by using an appropriate thread size, # but it works fine so far) self.ping_texture = Texture("FFTPing") self.ping_texture.setup_2d_texture(self.size, self.size, Texture.TFloat, Texture.FRgba32) self.pong_texture = Texture("FFTPong") self.pong_texture.setup_2d_texture(self.size, self.size, Texture.TFloat, Texture.FRgba32) self.source_tex = source_tex for tex in [self.ping_texture, self.pong_texture, source_tex]: tex.set_minfilter(Texture.FTNearest) tex.set_magfilter(Texture.FTNearest) tex.set_wrap_u(Texture.WMClamp) tex.set_wrap_v(Texture.WMClamp) # Pregenerate weights & indices for the shaders self._compute_weighting() # Pre generate the shaders, we have 2 passes: Horizontal and Vertical # which both execute log2(N) times with varying radii self.horizontal_fft_shader = Shader.load_compute( Shader.SLGLSL, "/$$rp/rpcore/water/shader/horizontal_fft.compute") self.horizontal_fft = NodePath("HorizontalFFT") self.horizontal_fft.set_shader(self.horizontal_fft_shader) self.horizontal_fft.set_shader_input("precomputedWeights", self.weights_lookup_tex) self.horizontal_fft.set_shader_input("N", LVecBase2i(self.size)) self.vertical_fft_shader = Shader.load_compute( Shader.SLGLSL, "/$$rp/rpcore/water/shader/vertical_fft.compute") self.vertical_fft = NodePath("VerticalFFT") self.vertical_fft.set_shader(self.vertical_fft_shader) self.vertical_fft.set_shader_input("precomputedWeights", self.weights_lookup_tex) self.vertical_fft.set_shader_input("N", LVecBase2i(self.size)) # Create a texture where the result is stored self.result_texture = Texture("Result") self.result_texture.setup2dTexture(self.size, self.size, Texture.TFloat, Texture.FRgba16) self.result_texture.set_minfilter(Texture.FTLinear) self.result_texture.set_magfilter(Texture.FTLinear) # Prepare the shader attributes, so we don't have to regenerate them # every frame -> That is VERY slow (3ms per fft instance) self._prepare_attributes()
def __init__(self): load_prc_file_data( "", """ textures-power-2 none window-type offscreen win-size 100 100 gl-coordinate-system default notify-level-display error print-pipe-types #f """) ShowBase.__init__(self) dest_tex = Texture() dest_tex.setup_2d_texture(2048, 2048, Texture.T_unsigned_byte, Texture.F_rgba8) cshader = Shader.load_compute(Shader.SL_GLSL, "grain.compute.glsl") node = NodePath("") node.set_shader(cshader) node.set_shader_input("DestTex", dest_tex) attr = node.get_attrib(ShaderAttrib) self.graphicsEngine.dispatch_compute((2048 // 16, 2048 // 16, 1), attr, self.win.get_gsg()) base.graphicsEngine.extract_texture_data(dest_tex, base.win.get_gsg()) # Convert to single channel img = PNMImage(2048, 2048, 1, 255) dest_tex.store(img) img.set_num_channels(1) tex = Texture() tex.load(img) tex.write("grain.txo.pz")
def __init__(self): load_prc_file_data("", """ textures-power-2 none window-type offscreen win-size 100 100 gl-coordinate-system default notify-level-display error print-pipe-types #f """) ShowBase.__init__(self) dest_tex = Texture() dest_tex.setup_2d_texture(2048, 2048, Texture.T_unsigned_byte, Texture.F_rgba8) cshader = Shader.load_compute(Shader.SL_GLSL, "grain.compute.glsl") node = NodePath("") node.set_shader(cshader) node.set_shader_input("DestTex", dest_tex) attr = node.get_attrib(ShaderAttrib) self.graphicsEngine.dispatch_compute( (2048 // 16, 2048 // 16, 1), attr, self.win.get_gsg()) base.graphicsEngine.extract_texture_data(dest_tex, base.win.get_gsg()) # Convert to single channel img = PNMImage(2048, 2048, 1, 255) dest_tex.store(img) img.set_num_channels(1) tex = Texture() tex.load(img) tex.write("grain.txo.pz")
def _create_shaders(self): """ Creates all the shaders used for precomputing """ self._shaders = {} resource_path = self._handle.get_shader_resource("eric_bruneton") for fname in listdir(resource_path): fpath = join(resource_path, fname) if isfile(fpath) and fname.endswith(".compute.glsl"): shader_name = fname.split(".")[0] shader_obj = Shader.load_compute(Shader.SL_GLSL, fpath) self._shaders[shader_name] = shader_obj
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 load_shader(cls, *args): """ Loads a shader from disk """ with timed_loading_operation(args): if len(args) == 1: return Shader.load_compute(Shader.SL_GLSL, args[0]) return Shader.load(Shader.SL_GLSL, *args)
def __init__(self, water_options): self.options = water_options self.options.size = 512 self.options.wind_dir.normalize() self.options.wave_amplitude *= 1e-7 self.displacement_tex = Texture("Displacement") self.displacement_tex.setup_2d_texture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.normal_tex = Texture("Normal") self.normal_tex.setup_2d_texture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.combine_shader = Shader.load_compute(Shader.SLGLSL, "/$$rp/rpcore/water/shader/combine.compute") self.pta_time = PTAFloat.emptyArray(1) # Create a gaussian random texture, as shaders aren't well suited # for that setRandomSeed(523) self.random_storage = PNMImage(self.options.size, self.options.size, 4) self.random_storage.setMaxval((2 ** 16) - 1) for x in range(self.options.size): for y in range(self.options.size): rand1 = self._get_gaussian_random() / 10.0 + 0.5 rand2 = self._get_gaussian_random() / 10.0 + 0.5 self.random_storage.setXel(x, y, float(rand1), float(rand2), 0) self.random_storage.setAlpha(x, y, 1.0) self.random_storage_tex = Texture("RandomStorage") self.random_storage_tex.load(self.random_storage) self.random_storage_tex.set_format(Texture.FRgba16) self.random_storage_tex.set_minfilter(Texture.FTNearest) self.random_storage_tex.set_magfilter(Texture.FTNearest) # Create the texture wwhere the intial height (H0 + Omega0) is stored. self.tex_initial_height = Texture("InitialHeight") self.tex_initial_height.setup_2d_texture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.tex_initial_height.set_minfilter(Texture.FTNearest) self.tex_initial_height.set_magfilter(Texture.FTNearest) # Create the shader which populates the initial height texture self.shader_initial_height = Shader.load_compute(Shader.SLGLSL, "/$$rp/rpcore/water/shader/initial_height.compute") self.node_initial_height = NodePath("initialHeight") self.node_initial_height.set_shader(self.shader_initial_height) self.node_initial_height.set_shader_input("dest", self.tex_initial_height) self.node_initial_height.set_shader_input( "N", LVecBase2i(self.options.size)) self.node_initial_height.set_shader_input( "patchLength", self.options.patch_length) self.node_initial_height.set_shader_input("windDir", self.options.wind_dir) self.node_initial_height.set_shader_input( "windSpeed", self.options.wind_speed) self.node_initial_height.set_shader_input( "waveAmplitude", self.options.wave_amplitude) self.node_initial_height.set_shader_input( "windDependency", self.options.wind_dependency) self.node_initial_height.set_shader_input( "randomTex", self.random_storage_tex) self.attr_initial_height = self.node_initial_height.get_attrib(ShaderAttrib) self.height_textures = [] for i in range(3): tex = Texture("Height") tex.setup_2d_texture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) tex.set_minfilter(Texture.FTNearest) tex.set_magfilter(Texture.FTNearest) tex.set_wrap_u(Texture.WMClamp) tex.set_wrap_v(Texture.WMClamp) self.height_textures.append(tex) # Also create the shader which updates the spectrum self.shader_update = Shader.load_compute(Shader.SLGLSL, "/$$rp/rpcore/water/shader/update.compute") self.node_update = NodePath("update") self.node_update.set_shader(self.shader_update) self.node_update.set_shader_input("outH0x", self.height_textures[0]) self.node_update.set_shader_input("outH0y", self.height_textures[1]) self.node_update.set_shader_input("outH0z", self.height_textures[2]) self.node_update.set_shader_input("initialHeight", self.tex_initial_height) self.node_update.set_shader_input("N", LVecBase2i(self.options.size)) self.node_update.set_shader_input("time", self.pta_time) self.attr_update = self.node_update.get_attrib(ShaderAttrib) # Create 3 FFTs self.fftX = GPUFFT(self.options.size, self.height_textures[0], self.options.normalization_factor) self.fftY = GPUFFT(self.options.size, self.height_textures[1], self.options.normalization_factor) self.fftZ = GPUFFT(self.options.size, self.height_textures[2], self.options.normalization_factor) self.combine_node = NodePath("Combine") self.combine_node.set_shader(self.combine_shader) self.combine_node.set_shader_input( "displacementX", self.fftX.get_result_texture()) self.combine_node.set_shader_input( "displacementY", self.fftY.get_result_texture()) self.combine_node.set_shader_input( "displacementZ", self.fftZ.get_result_texture()) self.combine_node.set_shader_input("normalDest", self.normal_tex) self.combine_node.set_shader_input( "displacementDest", self.displacement_tex) self.combine_node.set_shader_input( "N", LVecBase2i(self.options.size)) self.combine_node.set_shader_input( "choppyScale", self.options.choppy_scale) self.combine_node.set_shader_input( "gridLength", self.options.patch_length) # Store only the shader attrib as this is way faster self.attr_combine = self.combine_node.get_attrib(ShaderAttrib)