class SuperSamplingAA(PipelineNode): def __init__(self, pipeline): PipelineNode.__init__(self, pipeline) self.resolution = None @classmethod def reflect_inputs(cls): inputs = {} inputs['Color'] = Parameter('', Type.TEXTURE) return inputs @classmethod def reflect_outputs(cls): outputs = {} outputs['Color'] = Parameter('', Type.TEXTURE) return outputs def setup_render_targets(self, resolution): self.t_color = Texture(resolution, GL_RGBA16F) self.fbo = RenderTarget([self.t_color]) def execute(self, parameters): inputs = parameters['IN'] outputs = parameters['OUT'] if self.pipeline.resolution != self.resolution: self.setup_render_targets(self.pipeline.resolution) self.resolution = self.pipeline.resolution if self.pipeline.is_new_frame: self.fbo.clear([(0,0,0,0)]) if inputs['Color']: self.pipeline.blend_texture(inputs['Color'], self.fbo, 1.0 / (self.pipeline.sample_count + 1)) outputs['Color'] = self.t_color
def setup(self, create_fbos=True): self.spot_depth_t = TextureArray( (self.spot_resolution, self.spot_resolution), self.max_spots, GL_DEPTH_COMPONENT32F) self.sun_depth_t = TextureArray( (self.sun_resolution, self.sun_resolution), self.max_suns, GL_DEPTH_COMPONENT32F) self.point_depth_t = CubeMapArray( (self.point_resolution, self.point_resolution), self.max_points, GL_DEPTH_COMPONENT32F) if create_fbos: self.spot_fbos = [] for i in range(self.spot_depth_t.length): self.spot_fbos.append( RenderTarget([], ArrayLayerTarget(self.spot_depth_t, i))) self.sun_fbos = [] for i in range(self.sun_depth_t.length): self.sun_fbos.append( RenderTarget([], ArrayLayerTarget(self.sun_depth_t, i))) self.point_fbos = [] for i in range(self.point_depth_t.length * 6): self.point_fbos.append( RenderTarget([], ArrayLayerTarget(self.point_depth_t, i)))
def execute(self, parameters): from Malt.GL import GL from Malt.GL.Texture import Texture from Malt.GL.RenderTarget import RenderTarget if self.pipeline.resolution != self.resolution: for i in range(4): #TODO: Doesn't work with GL_RGBA? self.texture_targets[i] = Texture(self.pipeline.resolution, GL.GL_RGBA16F) self.render_target = RenderTarget(self.texture_targets) self.resolution = self.pipeline.resolution self.render_target.clear([(0,0,0,0)]*4) global _UNPACK_SHADER if _UNPACK_SHADER is None: _UNPACK_SHADER = self.pipeline.compile_shader_from_source(_UNPACK_SRC) _UNPACK_SHADER.textures['IN_PACKED'] = parameters['Packed Texture'] self.pipeline.draw_screen_pass(_UNPACK_SHADER, self.render_target, blend = False) parameters['A'] = self.texture_targets[0] parameters['B'] = self.texture_targets[1] parameters['C'] = self.texture_targets[2] parameters['D'] = self.texture_targets[3]
def setup(self, create_fbos=True): super().setup(False) self.spot_id_t = TextureArray( (self.spot_resolution, self.spot_resolution), self.max_spots, GL_R32F) self.sun_id_t = TextureArray( (self.sun_resolution, self.sun_resolution), self.max_suns * self.sun_cascades, GL_R32F) self.point_id_t = CubeMapArray( (self.point_resolution, self.point_resolution), self.max_points, GL_R32F) if create_fbos: self.spot_fbos = [] for i in range(self.spot_depth_t.length): self.spot_fbos.append( RenderTarget([ArrayLayerTarget(self.spot_id_t, i)], ArrayLayerTarget(self.spot_depth_t, i))) self.sun_fbos = [] for i in range(self.sun_depth_t.length): self.sun_fbos.append( RenderTarget([ArrayLayerTarget(self.sun_id_t, i)], ArrayLayerTarget(self.sun_depth_t, i))) self.point_fbos = [] for i in range(self.point_depth_t.length * 6): self.point_fbos.append( RenderTarget([ArrayLayerTarget(self.point_id_t, i)], ArrayLayerTarget(self.point_depth_t, i)))
def execute(self, parameters): inputs = parameters['IN'] outputs = parameters['OUT'] material = parameters['PASS_MATERIAL'] custom_io = parameters['CUSTOM_IO'] if self.pipeline.resolution != self.resolution or self.custom_io != custom_io: self.texture_targets = {} for io in custom_io: if io['io'] == 'out': if io['type'] == 'Texture':#TODO self.texture_targets[io['name']] = Texture(self.pipeline.resolution, GL.GL_RGBA16F) self.render_target = RenderTarget([*self.texture_targets.values()]) self.resolution = self.pipeline.resolution self.custom_io = custom_io self.render_target.clear([(0,0,0,0)]*len(self.texture_targets)) if material and material.shader and 'SHADER' in material.shader: shader = material.shader['SHADER'] for io in custom_io: if io['io'] == 'in': if io['type'] == 'Texture':#TODO from Malt.SourceTranspiler import GLSLTranspiler glsl_name = GLSLTranspiler.custom_io_reference('IN', 'SCREEN_SHADER', io['name']) shader.textures[glsl_name] = inputs[io['name']] self.pipeline.common_buffer.shader_callback(shader) shader.uniforms['RENDER_LAYER_MODE'].set_value(False) self.pipeline.draw_screen_pass(shader, self.render_target) for io in custom_io: if io['io'] == 'out': if io['type'] == 'Texture':#TODO outputs[io['name']] = self.texture_targets[io['name']]
def setup_render_targets(self, resolution, t_depth, custom_io): self.custom_targets = {} for io in custom_io: if io['io'] == 'out' and io['type'] == 'Texture': #TODO self.custom_targets[io['name']] = Texture( resolution, GL.GL_RGBA16F) self.t_depth = t_depth self.fbo = RenderTarget([*self.custom_targets.values()], self.t_depth)
class MiniPipeline(Pipeline): DEFAULT_SHADER = None def __init__(self, plugins=[]): super().__init__(plugins) self.parameters.world['Background Color'] = Parameter((0.5,0.5,0.5,1), Type.FLOAT, 4) if MiniPipeline.DEFAULT_SHADER is None: source = ''' #include "Common.glsl" #ifdef VERTEX_SHADER void main() { DEFAULT_VERTEX_SHADER(); } #endif #ifdef PIXEL_SHADER layout (location = 0) out vec4 RESULT; void main() { PIXEL_SETUP_INPUT(); RESULT = vec4(1); } #endif ''' MiniPipeline.DEFAULT_SHADER = self.compile_material_from_source('mesh', source) self.default_shader = MiniPipeline.DEFAULT_SHADER def compile_material_from_source(self, material_type, source, include_paths=[]): return { 'MAIN_PASS' : self.compile_shader_from_source( source, include_paths, ['MAIN_PASS'] ) } def setup_render_targets(self, resolution): self.t_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.t_main_color = Texture(resolution, GL_RGBA32F) self.fbo_main = RenderTarget([self.t_main_color], self.t_depth) def do_render(self, resolution, scene, is_final_render, is_new_frame): shader_resources = { 'COMMON_UNIFORMS' : self.common_buffer } self.fbo_main.clear([scene.world_parameters['Background Color']], 1) self.draw_scene_pass(self.fbo_main, scene.batches, 'MAIN_PASS', self.default_shader['MAIN_PASS'], shader_resources) return { 'COLOR' : self.t_main_color }
def execute(self, parameters): inputs = parameters['IN'] outputs = parameters['OUT'] material = parameters['PASS_MATERIAL'] custom_io = parameters['CUSTOM_IO'] deferred_mode = inputs['Layer Only'] scene = inputs['Scene'] t_normal_depth = inputs['Normal Depth'] t_id = inputs['ID'] shader_resources = {} if scene: shader_resources = scene.shader_resources.copy() if t_normal_depth: shader_resources['IN_NORMAL_DEPTH'] = TextureShaderResource('IN_NORMAL_DEPTH', t_normal_depth) if t_id: shader_resources['IN_ID'] = TextureShaderResource('IN_ID', t_id) if self.pipeline.resolution != self.resolution or self.custom_io != custom_io: self.texture_targets = {} for io in custom_io: if io['io'] == 'out': if io['type'] == 'Texture':#TODO self.texture_targets[io['name']] = Texture(self.pipeline.resolution, GL.GL_RGBA16F) self.render_target = RenderTarget([*self.texture_targets.values()]) self.resolution = self.pipeline.resolution self.custom_io = custom_io self.render_target.clear([(0,0,0,0)]*len(self.texture_targets)) if material and material.shader and 'SHADER' in material.shader: shader = material.shader['SHADER'] for io in custom_io: if io['io'] == 'in': if io['type'] == 'Texture':#TODO from Malt.SourceTranspiler import GLSLTranspiler glsl_name = GLSLTranspiler.custom_io_reference('IN', 'SCREEN_SHADER', io['name']) shader.textures[glsl_name] = inputs[io['name']] self.pipeline.common_buffer.bind(shader.uniform_blocks['COMMON_UNIFORMS']) for resource in shader_resources.values(): resource.shader_callback(shader) shader.uniforms['RENDER_LAYER_MODE'].set_value(True) shader.uniforms['DEFERRED_MODE'].set_value(deferred_mode) self.pipeline.draw_screen_pass(shader, self.render_target) for io in custom_io: if io['io'] == 'out': if io['type'] == 'Texture':#TODO outputs[io['name']] = self.texture_targets[io['name']]
def setup_render_targets(self, resolution, custom_io): self.opaque_targets = {} self.transparent_targets = {} self.color_targets = {} for io in custom_io: if io['io'] == 'out' and io['type'] == 'Texture':#TODO self.opaque_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.transparent_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.color_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.fbo_opaque = RenderTarget([*self.opaque_targets.values()]) self.fbo_transparent = RenderTarget([*self.transparent_targets.values()]) self.fbo_color = RenderTarget([*self.color_targets.values()])
class Unpack8bitTextures(PipelineNode): def __init__(self, pipeline): self.pipeline = pipeline self.resolution = None self.texture_targets = [None]*4 self.render_target = None @classmethod def reflect_inputs(cls): return { 'Packed Texture' : Parameter('usampler2D', Type.OTHER) } @classmethod def reflect_outputs(cls): return { 'A' : Parameter('', Type.TEXTURE), 'B' : Parameter('', Type.TEXTURE), 'C' : Parameter('', Type.TEXTURE), 'D' : Parameter('', Type.TEXTURE), } def execute(self, parameters): from Malt.GL import GL from Malt.GL.Texture import Texture from Malt.GL.RenderTarget import RenderTarget if self.pipeline.resolution != self.resolution: for i in range(4): #TODO: Doesn't work with GL_RGBA? self.texture_targets[i] = Texture(self.pipeline.resolution, GL.GL_RGBA16F) self.render_target = RenderTarget(self.texture_targets) self.resolution = self.pipeline.resolution self.render_target.clear([(0,0,0,0)]*4) global _UNPACK_SHADER if _UNPACK_SHADER is None: _UNPACK_SHADER = self.pipeline.compile_shader_from_source(_UNPACK_SRC) _UNPACK_SHADER.textures['IN_PACKED'] = parameters['Packed Texture'] self.pipeline.draw_screen_pass(_UNPACK_SHADER, self.render_target, blend = False) parameters['A'] = self.texture_targets[0] parameters['B'] = self.texture_targets[1] parameters['C'] = self.texture_targets[2] parameters['D'] = self.texture_targets[3]
def load(self, pipeline, depth_texture, scene): self.custom_shading_count = 0 for i, light in enumerate(scene.lights): custom_shading_index = -1 if light.parameters['Shader'] is not None: custom_shading_index = self.custom_shading_count self.custom_shading_count += 1 self.data.custom_shading_index[i] = custom_shading_index self.UBO.load_data(self.data) if self.custom_shading_count == 0: return lights = [l for l in scene.lights if l.parameters['Shader'] is not None] tex = self.texture if tex is None or tex.resolution != depth_texture.resolution or tex.length < len(lights): self.texture = TextureArray(depth_texture.resolution, len(lights), GL_RGB32F) self.fbos = [] for i in range(len(lights)): self.fbos.append(RenderTarget([ArrayLayerTarget(self.texture, i)])) for i, light in enumerate(lights): material = light.parameters['Shader'] if material.shader and 'SHADER' in material.shader.keys(): shader = material.shader['SHADER'] pipeline.common_buffer.bind(shader.uniform_blocks['COMMON_UNIFORMS']) pipeline.lights_buffer.bind(shader.uniform_blocks['SCENE_LIGHTS']) shader.textures['IN_DEPTH'] = depth_texture if 'LIGHT_INDEX' in shader.uniforms: shader.uniforms['LIGHT_INDEX'].set_value(i) pipeline.draw_screen_pass(shader, self.fbos[i])
def do_render(self, resolution, scene, is_final_render, is_new_frame): #SETUP SAMPLING if self.sampling_grid_size != scene.world_parameters['Samples.Grid Size']: self.sampling_grid_size = scene.world_parameters['Samples.Grid Size'] self.samples = None self.is_new_frame = is_new_frame sample_offset = self.get_sample(scene.world_parameters['Samples.Width']) opaque_batches, transparent_batches = self.get_scene_batches(scene) self.common_buffer.load(scene, resolution, sample_offset, self.sample_count) scene.shader_resources = { 'COMMON_UNIFORMS' : self.common_buffer } result = { 'COLOR': None, 'DEPTH': None, } graph = scene.world_parameters['Render'] if graph: IN = {'Scene' : scene} OUT = {'Color' : None} self.graphs['Render'].run_source(self, graph['source'], graph['parameters'], IN, OUT) result = OUT result['COLOR'] = result['Color'] result['DEPTH'] = result['Depth'] #COMPOSITE DEPTH if is_final_render and result['DEPTH'] is None: if self.sample_count == len(self.samples) - 1: normal_depth = Texture(resolution, GL_RGBA32F) target = RenderTarget([normal_depth], Texture(resolution, GL_DEPTH_COMPONENT32F)) target.clear([(0,0,1,1)], 1) self.common_buffer.load(scene, resolution) self.draw_scene_pass(target, opaque_batches, 'PRE_PASS', self.default_shader, scene.shader_resources) result['DEPTH'] = self.composite_depth.render(self, self.common_buffer, normal_depth, depth_channel=3) return result
def setup(self, new_buffers, resolution, scene, scene_update, renderdoc_capture): if self.resolution != resolution: self.resolution = resolution self.pbos_inactive.extend(self.pbos_active) self.pbos_active = [] assert (new_buffers is not None) if self.bit_depth == 8: optimal_format = GL_UNSIGNED_BYTE if glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_READ_PIXELS, 1) != GL_ZERO: optimal_format = glGetInternalformativ( GL_TEXTURE_2D, GL_RGBA8, GL_TEXTURE_IMAGE_TYPE, 1) try: self.final_texture = Texture(resolution, GL_RGBA8, optimal_format, pixel_format=GL_RGBA) except: # Fallback to unsigned byte, just in case self.final_texture = Texture(resolution, GL_RGBA8, GL_UNSIGNED_BYTE, pixel_format=GL_RGBA) self.final_texture.channel_size = 1 self.final_target = RenderTarget([self.final_texture]) if new_buffers: self.buffers = new_buffers self.sample_index = 0 self.is_new_frame = True self.needs_more_samples = True self.renderdoc_capture = renderdoc_capture self.stat_time_start = time.perf_counter() if scene_update or self.scene is None: for key, proxy in scene.proxys.items(): proxy.resolve() for obj in scene.objects: obj.matrix = (ctypes.c_float * 16)(*obj.matrix) scene.batches = self.pipeline.build_scene_batches(scene.objects) self.scene = scene else: self.scene.camera = scene.camera self.scene.time = scene.time self.scene.frame = scene.frame
def setup(self, texture, buffer): self.buffer = buffer render_target = RenderTarget([texture]) w,h = texture.resolution size = w*h*4*4 if self.size != size: self.size = size glDeleteBuffers(1, self.handle) glGenBuffers(1, self.handle) glBindBuffer(GL_PIXEL_PACK_BUFFER, self.handle[0]) glBufferData(GL_PIXEL_PACK_BUFFER, size, None, GL_STREAM_READ) glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) render_target.bind() GL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0) glBindBuffer(GL_PIXEL_PACK_BUFFER, self.handle[0]) GL.glReadPixels(0, 0, w, h, texture.format, texture.data_format, 0) glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) if self.sync: glDeleteSync(self.sync) self.sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)
def render(self, pipeline, common_buffer, depth_texture, depth_channel=0): if self.t is None or self.t.resolution != depth_texture.resolution: self.t = Texture(depth_texture.resolution, GL_R32F) self.fbo = RenderTarget([self.t]) if self.shader == None: global _SHADER if _SHADER is None: _SHADER = pipeline.compile_shader_from_source(_shader_src) self.shader = _SHADER self.shader.textures['DEPTH_TEXTURE'] = depth_texture self.shader.uniforms['DEPTH_CHANNEL'].set_value(depth_channel) common_buffer.shader_callback(self.shader) pipeline.draw_screen_pass(self.shader, self.fbo) return self.t
def render(self, pipeline, common_buffer, depth_texture): if self.t is None or self.t.resolution != depth_texture.resolution: self.t = Texture(depth_texture.resolution, GL_R32F) self.fbo = RenderTarget([self.t]) if self.shader == None: global _SHADER if _SHADER is None: _SHADER = pipeline.compile_shader_from_source(_shader_src) self.shader = _SHADER self.shader.textures['DEPTH_TEXTURE'] = depth_texture self.shader.bind() common_buffer.bind(self.shader.uniform_blocks['COMMON_UNIFORMS']) pipeline.draw_screen_pass(self.shader, self.fbo) return self.t
def setup_render_targets(self, resolution, custom_io): self.t_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.t_normal_depth = Texture(resolution, GL_RGBA32F) self.t_id = Texture(resolution, GL_RGBA16UI, min_filter=GL_NEAREST, mag_filter=GL_NEAREST) self.custom_targets = {} for io in custom_io: if io['io'] == 'out' and io['type'] == 'Texture':#TODO self.custom_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.fbo = RenderTarget([self.t_normal_depth, self.t_id, *self.custom_targets.values()], self.t_depth) self.t_last_layer_id = Texture(resolution, GL_R16UI, min_filter=GL_NEAREST, mag_filter=GL_NEAREST) self.fbo_last_layer_id = RenderTarget([self.t_last_layer_id]) self.t_opaque_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_opaque_depth = RenderTarget([], self.t_opaque_depth) self.t_transparent_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_transparent_depth = RenderTarget([], self.t_transparent_depth)
def setup_render_targets(self, resolution): self.t_color = Texture(resolution, GL_RGBA16F) self.fbo = RenderTarget([self.t_color])
class RenderLayers(PipelineNode): def __init__(self, pipeline): PipelineNode.__init__(self, pipeline) self.resolution = None self.texture_targets = {} self.render_target = None self.custom_io = [] @staticmethod def get_pass_type(): return 'Render Layer.Render Layer' @classmethod def reflect_inputs(cls): inputs = {} inputs['Scene'] = Parameter('Scene', Type.OTHER) inputs['Transparent Layers'] = Parameter(4, Type.INT) inputs['Transparent Layers @ Preview'] = Parameter(2, Type.INT) return inputs @classmethod def reflect_outputs(cls): outputs = {} return outputs def setup_render_targets(self, resolution, custom_io): self.opaque_targets = {} self.transparent_targets = {} self.color_targets = {} for io in custom_io: if io['io'] == 'out' and io['type'] == 'Texture':#TODO self.opaque_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.transparent_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.color_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.fbo_opaque = RenderTarget([*self.opaque_targets.values()]) self.fbo_transparent = RenderTarget([*self.transparent_targets.values()]) self.fbo_color = RenderTarget([*self.color_targets.values()]) def blend_transparency(self, back_textures, front_textures, fbo): global _BLEND_TRANSPARENCY_SHADER if _BLEND_TRANSPARENCY_SHADER is None: _BLEND_TRANSPARENCY_SHADER = self.pipeline.compile_shader_from_source('#include "Passes/BlendTransparency.glsl"') for i in range(len(fbo.targets)): _BLEND_TRANSPARENCY_SHADER.textures[f'IN_BACK[{str(i)}]'] = back_textures[i] _BLEND_TRANSPARENCY_SHADER.textures[f'IN_FRONT[{str(i)}]'] = front_textures[i] self.pipeline.draw_screen_pass(_BLEND_TRANSPARENCY_SHADER, fbo) def execute(self, parameters): inputs = parameters['IN'] outputs = parameters['OUT'] custom_io = parameters['CUSTOM_IO'] graph = parameters['PASS_GRAPH'] scene = inputs['Scene'] if scene and graph: if self.pipeline.resolution != self.resolution or self.custom_io != custom_io: self.setup_render_targets(self.pipeline.resolution, custom_io) self.resolution = self.pipeline.resolution self.custom_io = custom_io self.fbo_color.clear([(0,0,0,0)]*len(self.fbo_color.targets)) self.fbo_transparent.clear([(0,0,0,0)]*len(self.fbo_transparent.targets)) self.layer_index = 0 self.layer_count = inputs['Transparent Layers'] + 1 graph['parameters']['__RENDER_LAYERS__'] = self for i in range(self.layer_count): graph['parameters']['__LAYER_INDEX__'] = self.layer_index graph['parameters']['__LAYER_COUNT__'] = self.layer_count self.pipeline.graphs['Render Layer'].run_source(self.pipeline, graph['source'], graph['parameters'], inputs, outputs) results = [] for io in self.custom_io: if io['io'] == 'out' and io['type'] == 'Texture': results.append(outputs[io['name']]) if i == 0: self.pipeline.copy_textures(self.fbo_opaque, results) else: self.blend_transparency(results, self.fbo_transparent.targets, self.fbo_color) self.pipeline.copy_textures(self.fbo_transparent, self.fbo_color.targets) self.layer_index += 1 self.blend_transparency(self.fbo_opaque.targets, self.fbo_transparent.targets, self.fbo_color) outputs.update(self.color_targets)
class MainPass(PipelineNode): def __init__(self, pipeline): PipelineNode.__init__(self, pipeline) self.resolution = None self.t_depth = None @staticmethod def get_pass_type(): return 'Mesh.MAIN_PASS_PIXEL_SHADER' @classmethod def reflect_inputs(cls): inputs = {} inputs['Scene'] = Parameter('Scene', Type.OTHER) inputs['Normal Depth'] = Parameter('', Type.TEXTURE) inputs['ID'] = Parameter('', Type.TEXTURE) return inputs @classmethod def reflect_outputs(cls): outputs = {} return outputs def setup_render_targets(self, resolution, t_depth, custom_io): self.custom_targets = {} for io in custom_io: if io['io'] == 'out' and io['type'] == 'Texture': #TODO self.custom_targets[io['name']] = Texture( resolution, GL.GL_RGBA16F) self.t_depth = t_depth self.fbo = RenderTarget([*self.custom_targets.values()], self.t_depth) def execute(self, parameters): inputs = parameters['IN'] outputs = parameters['OUT'] custom_io = parameters['CUSTOM_IO'] scene = inputs['Scene'] if scene is None: return t_normal_depth = inputs['Normal Depth'] t_id = inputs['ID'] shader_resources = scene.shader_resources.copy() if t_normal_depth: shader_resources['IN_NORMAL_DEPTH'] = TextureShaderResource( 'IN_NORMAL_DEPTH', t_normal_depth) if t_id: shader_resources['IN_ID'] = TextureShaderResource('IN_ID', t_id) t_depth = shader_resources['T_DEPTH'].texture if self.pipeline.resolution != self.resolution or self.custom_io != custom_io or t_depth != self.t_depth: self.setup_render_targets(self.pipeline.resolution, t_depth, custom_io) self.resolution = self.pipeline.resolution self.custom_io = custom_io for io in custom_io: if io['io'] == 'in': if io['type'] == 'Texture': #TODO from Malt.SourceTranspiler import GLSLTranspiler glsl_name = GLSLTranspiler.custom_io_reference( 'IN', 'MAIN_PASS_PIXEL_SHADER', io['name']) shader_resources['CUSTOM_IO' + glsl_name] = TextureShaderResource( glsl_name, inputs[io['name']]) self.fbo.clear([(0, 0, 0, 0)] * len(self.fbo.targets)) self.pipeline.draw_scene_pass( self.fbo, scene.batches, 'MAIN_PASS', self.pipeline.default_shader['MAIN_PASS'], shader_resources, GL_EQUAL) outputs.update(self.custom_targets)
class NPR_Pipeline(Pipeline): def __init__(self): super().__init__() self.sampling_grid_size = 2 self.parameters.world['Background Color'] = Parameter( (0.5, 0.5, 0.5, 1), Type.FLOAT, 4) self.parameters.scene['Line Width Max'] = Parameter(10, Type.INT) self.parameters.scene['Samples Grid Size Preview'] = Parameter( 4, Type.INT) self.parameters.scene['Samples Grid Size Render'] = Parameter( 8, Type.INT) self.parameters.scene['Samples Width'] = Parameter(1.5, Type.FLOAT) self.parameters.scene[ 'Shadow Cascades Distribution Exponent'] = Parameter(21, Type.INT) self.parameters.scene['ShadowMaps Spot Resolution'] = Parameter( 2048, Type.INT) self.parameters.scene['ShadowMaps Sun Resolution'] = Parameter( 2048, Type.INT) self.parameters.scene['ShadowMaps Point Resolution'] = Parameter( 2048, Type.INT) self.parameters.scene['Transparency Layers'] = Parameter(4, Type.INT) self.parameters.light['Shader'] = MaterialParameter('', 'light') global _DEFAULT_SHADER if _DEFAULT_SHADER is None: _DEFAULT_SHADER = self.compile_material_from_source( 'mesh', _DEFAULT_SHADER_SRC) self.default_shader = _DEFAULT_SHADER global _BLEND_TRANSPARENCY_SHADER if _BLEND_TRANSPARENCY_SHADER is None: _BLEND_TRANSPARENCY_SHADER = self.compile_shader_from_source( _BLEND_TRANSPARENCY_SHADER_SRC) self.blend_transparency_shader = _BLEND_TRANSPARENCY_SHADER self.common_buffer = Common.CommonBuffer() self.lights_buffer = Lighting.get_lights_buffer() self.shadowmaps_opaque, self.shadowmaps_transparent = NPR_Lighting.get_shadow_maps( ) self.custom_light_shading = NPR_Lighting.NPR_LightShaders() self.line_rendering = Line.LineRendering() self.composite_depth = DepthToCompositeDepth.CompositeDepth() def compile_material_from_source(self, material_type, source, include_paths=[]): if material_type == 'mesh': return { 'PRE_PASS': self.compile_shader_from_source( source, include_paths, ['IS_MESH_SHADER', 'PRE_PASS']), 'MAIN_PASS': self.compile_shader_from_source( source, include_paths, ['IS_MESH_SHADER', 'MAIN_PASS']), 'SHADOW_PASS': self.compile_shader_from_source( source, include_paths, ['IS_MESH_SHADER', 'SHADOW_PASS']) } elif material_type == 'screen': return { 'SHADER': self.compile_shader_from_source(source, include_paths, ['IS_SCREEN_SHADER']) } elif material_type == 'light': return { 'SHADER': self.compile_shader_from_source(source, include_paths, ['IS_LIGHT_SHADER']) } else: return 'Invalid material type. Valid extensions are .mesh.glsl, .light.glsl and .screen.glsl' def setup_render_targets(self, resolution): self.t_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.t_prepass_normal_depth = Texture(resolution, GL_RGBA32F) self.t_prepass_id = Texture(resolution, GL_R32F) self.fbo_prepass = RenderTarget( [self.t_prepass_normal_depth, self.t_prepass_id], self.t_depth) self.t_last_layer_id = Texture(resolution, GL_R32F) self.fbo_last_layer_id = RenderTarget([self.t_last_layer_id]) self.t_main_color = Texture(resolution, GL_RGBA32F) self.t_line_color = Texture(resolution, GL_RGBA32F) self.t_line_data = Texture(resolution, GL_RGB32F) self.fbo_main = RenderTarget( [self.t_main_color, self.t_line_color, self.t_line_data], self.t_depth) self.t_opaque_color = Texture(resolution, GL_RGB32F) self.t_opaque_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_opaque = RenderTarget([self.t_opaque_color], self.t_opaque_depth) self.t_transparent_color = Texture(resolution, GL_RGBA32F) self.t_transparent_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_transparent = RenderTarget([self.t_transparent_color], self.t_transparent_depth) self.t_color = Texture(resolution, GL_RGBA32F) self.fbo_color = RenderTarget([self.t_color]) self.t_color_accumulate = Texture(resolution, GL_RGB32F) self.fbo_accumulate = RenderTarget([self.t_color_accumulate]) def get_samples(self, width=1.0): return Sampling.get_RGSS_samples(self.sampling_grid_size, width) def do_render(self, resolution, scene, is_final_render, is_new_frame): #SETUP SAMPLING if is_final_render: self.sampling_grid_size = scene.parameters[ 'Samples Grid Size Render'] else: self.sampling_grid_size = scene.parameters[ 'Samples Grid Size Preview'] sample_offset = self.get_samples( scene.parameters['Samples Width'])[self.sample_count] #SETUP SCENE BATCHES opaque_batches = {} transparent_batches = {} for material, meshes in scene.batches.items(): if material and material.shader: if material.shader['MAIN_PASS'].uniforms[ 'Settings.Transparency'].value[0] == True: transparent_batches[material] = meshes continue opaque_batches[material] = meshes #SETUP UNIFORM BLOCKS self.common_buffer.load(scene, resolution, sample_offset, self.sample_count) self.lights_buffer.load( scene, Lighting.SUN_CASCADES, scene.parameters['Shadow Cascades Distribution Exponent']) self.shadowmaps_opaque.load( scene, scene.parameters['ShadowMaps Spot Resolution'], scene.parameters['ShadowMaps Sun Resolution'], scene.parameters['ShadowMaps Point Resolution']) self.shadowmaps_transparent.load( scene, scene.parameters['ShadowMaps Spot Resolution'], scene.parameters['ShadowMaps Sun Resolution'], scene.parameters['ShadowMaps Point Resolution']) UBOS = { 'COMMON_UNIFORMS': self.common_buffer, 'SCENE_LIGHTS': self.lights_buffer } #RENDER SHADOWMAPS def render_shadow_passes(matrices, fbos_opaque, fbos_transparent): for i, matrix_pair in enumerate(matrices): camera, projection = matrix_pair self.common_buffer.load(scene, fbos_opaque[i].resolution, sample_offset, self.sample_count, camera, projection) self.draw_scene_pass(fbos_opaque[i], opaque_batches, 'SHADOW_PASS', self.default_shader['SHADOW_PASS'], UBOS) self.draw_scene_pass(fbos_transparent[i], transparent_batches, 'SHADOW_PASS', self.default_shader['SHADOW_PASS'], UBOS) render_shadow_passes(self.lights_buffer.spot_matrices, self.shadowmaps_opaque.spot_fbos, self.shadowmaps_transparent.spot_fbos) glEnable(GL_DEPTH_CLAMP) render_shadow_passes(self.lights_buffer.sun_matrices, self.shadowmaps_opaque.sun_fbos, self.shadowmaps_transparent.sun_fbos) glDisable(GL_DEPTH_CLAMP) render_shadow_passes(self.lights_buffer.point_matrices, self.shadowmaps_opaque.point_fbos, self.shadowmaps_transparent.point_fbos) #SCENE RENDER #Load scene camera settings self.common_buffer.load(scene, resolution, sample_offset, self.sample_count) result = self.draw_layer(opaque_batches, scene, scene.world_parameters['Background Color']) self.copy_textures(self.fbo_opaque, [result], self.t_depth) self.fbo_transparent.clear([(0, 0, 0, 0)], -1) self.fbo_last_layer_id.clear([0]) for i in range(scene.parameters['Transparency Layers']): result = self.draw_layer(transparent_batches, scene) self.copy_textures(self.fbo_last_layer_id, [self.t_prepass_id]) self.blend_transparency_shader.textures['IN_BACK'] = result self.blend_transparency_shader.textures[ 'IN_FRONT'] = self.t_transparent_color self.draw_screen_pass(self.blend_transparency_shader, self.fbo_color) self.copy_textures(self.fbo_transparent, [self.t_color], self.t_depth) self.blend_transparency_shader.textures[ 'IN_BACK'] = self.t_opaque_color self.blend_transparency_shader.textures[ 'IN_FRONT'] = self.t_transparent_color self.draw_screen_pass(self.blend_transparency_shader, self.fbo_color) # TEMPORAL SUPER-SAMPLING ACCUMULATION self.blend_texture(self.t_color, self.fbo_accumulate, 1.0 / (self.sample_count + 1)) #COMPOSITE DEPTH composite_depth = None if is_final_render: composite_depth = self.composite_depth.render( self, self.common_buffer, self.t_opaque_depth) return { 'COLOR': self.t_color_accumulate, 'DEPTH': composite_depth, } def draw_layer(self, batches, scene, background_color=(0, 0, 0, 0)): UBOS = { 'COMMON_UNIFORMS': self.common_buffer, 'SCENE_LIGHTS': self.lights_buffer } callbacks = [ lambda shader: self.shadowmaps_opaque.shader_callback(shader), lambda shader: self.shadowmaps_transparent.shader_callback(shader), ] #PRE-PASS textures = { 'IN_OPAQUE_DEPTH': self.t_opaque_depth, 'IN_TRANSPARENT_DEPTH': self.t_transparent_depth, 'IN_LAST_ID': self.t_last_layer_id, } self.fbo_prepass.clear([(0, 0, 1, 1), (0, 0, 0, 0)], 1, 0) self.draw_scene_pass(self.fbo_prepass, batches, 'PRE_PASS', self.default_shader['PRE_PASS'], UBOS, {}, textures, callbacks) #CUSTOM LIGHT SHADING self.custom_light_shading.load(self, self.t_depth, scene) callbacks.append( lambda shader: self.custom_light_shading.shader_callback(shader)) #MAIN-PASS textures = { 'IN_NORMAL_DEPTH': self.t_prepass_normal_depth, 'IN_ID': self.t_prepass_id, 'IN_OPAQUE_DEPTH': self.t_opaque_depth, 'IN_TRANSPARENT_DEPTH': self.t_transparent_depth, 'IN_LAST_ID': self.t_last_layer_id, } self.fbo_main.clear([background_color, (0, 0, 0, 1), (-1, -1, -1, -1)]) self.draw_scene_pass(self.fbo_main, batches, 'MAIN_PASS', self.default_shader['MAIN_PASS'], UBOS, {}, textures, callbacks) #COMPOSITE LINE composited_line = self.line_rendering.composite_line( scene.parameters['Line Width Max'], self, self.common_buffer, self.t_main_color, self.t_depth, self.t_prepass_id, self.t_line_color, self.t_line_data) return composited_line
def setup_render_targets(self, resolution): self.t_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.t_prepass_normal_depth = Texture(resolution, GL_RGBA32F) self.t_prepass_id = Texture(resolution, GL_R32F) self.fbo_prepass = RenderTarget( [self.t_prepass_normal_depth, self.t_prepass_id], self.t_depth) self.t_last_layer_id = Texture(resolution, GL_R32F) self.fbo_last_layer_id = RenderTarget([self.t_last_layer_id]) self.t_main_color = Texture(resolution, GL_RGBA32F) self.t_line_color = Texture(resolution, GL_RGBA32F) self.t_line_data = Texture(resolution, GL_RGB32F) self.fbo_main = RenderTarget( [self.t_main_color, self.t_line_color, self.t_line_data], self.t_depth) self.t_opaque_color = Texture(resolution, GL_RGB32F) self.t_opaque_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_opaque = RenderTarget([self.t_opaque_color], self.t_opaque_depth) self.t_transparent_color = Texture(resolution, GL_RGBA32F) self.t_transparent_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_transparent = RenderTarget([self.t_transparent_color], self.t_transparent_depth) self.t_color = Texture(resolution, GL_RGBA32F) self.fbo_color = RenderTarget([self.t_color]) self.t_color_accumulate = Texture(resolution, GL_RGB32F) self.fbo_accumulate = RenderTarget([self.t_color_accumulate])
class PrePass(PipelineNode): def __init__(self, pipeline): PipelineNode.__init__(self, pipeline) self.resolution = None self.custom_io = [] self.npr_light_shaders = NPR_LightShaders() @staticmethod def get_pass_type(): return 'Mesh.PRE_PASS_PIXEL_SHADER' @classmethod def reflect_inputs(cls): inputs = {} inputs['Scene'] = Parameter('Scene', Type.OTHER) return inputs @classmethod def reflect_outputs(cls): outputs = {} outputs['Scene'] = Parameter('Scene', Type.OTHER) outputs['Normal Depth'] = Parameter('', Type.TEXTURE) outputs['ID'] = Parameter('', Type.TEXTURE) return outputs def setup_render_targets(self, resolution, custom_io): self.t_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.t_normal_depth = Texture(resolution, GL_RGBA32F) self.t_id = Texture(resolution, GL_RGBA16UI, min_filter=GL_NEAREST, mag_filter=GL_NEAREST) self.custom_targets = {} for io in custom_io: if io['io'] == 'out' and io['type'] == 'Texture':#TODO self.custom_targets[io['name']] = Texture(resolution, GL.GL_RGBA16F) self.fbo = RenderTarget([self.t_normal_depth, self.t_id, *self.custom_targets.values()], self.t_depth) self.t_last_layer_id = Texture(resolution, GL_R16UI, min_filter=GL_NEAREST, mag_filter=GL_NEAREST) self.fbo_last_layer_id = RenderTarget([self.t_last_layer_id]) self.t_opaque_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_opaque_depth = RenderTarget([], self.t_opaque_depth) self.t_transparent_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.fbo_transparent_depth = RenderTarget([], self.t_transparent_depth) def execute(self, parameters): inputs = parameters['IN'] outputs = parameters['OUT'] custom_io = parameters['CUSTOM_IO'] scene = inputs['Scene'] is_opaque_pass = parameters['__GLOBALS__']['__LAYER_INDEX__'] == 0 if self.pipeline.resolution != self.resolution or self.custom_io != custom_io: self.setup_render_targets(self.pipeline.resolution, custom_io) self.resolution = self.pipeline.resolution self.custom_io = custom_io import copy scene = copy.copy(scene) opaque_batches, transparent_batches = self.pipeline.get_scene_batches(scene) scene.batches = opaque_batches if is_opaque_pass else transparent_batches shader_resources = scene.shader_resources.copy() shader_resources.update({ 'IN_OPAQUE_DEPTH': TextureShaderResource('IN_OPAQUE_DEPTH', self.t_opaque_depth), 'IN_TRANSPARENT_DEPTH': TextureShaderResource('IN_TRANSPARENT_DEPTH', self.t_transparent_depth), 'IN_LAST_ID': TextureShaderResource('IN_LAST_ID', self.t_last_layer_id), }) self.fbo.clear([(0,0,1,1), (0,0,0,0)] + [(0,0,0,0)]*len(self.custom_targets), 1) self.pipeline.draw_scene_pass(self.fbo, scene.batches, 'PRE_PASS', self.pipeline.default_shader['PRE_PASS'], shader_resources) if is_opaque_pass: self.fbo_last_layer_id.clear([(0,0,0,0)]) self.fbo_transparent_depth.clear([], -1) self.pipeline.copy_textures(self.fbo_opaque_depth, [], self.t_depth) else: self.pipeline.copy_textures(self.fbo_last_layer_id, [self.t_id]) self.pipeline.copy_textures(self.fbo_transparent_depth, [], self.t_depth) #CUSTOM LIGHT SHADERS self.npr_light_shaders.load(self.pipeline, self.t_depth, scene) scene.shader_resources = scene.shader_resources.copy() scene.shader_resources.update({ 'LIGHTS_CUSTOM_SHADING': self.npr_light_shaders, 'IN_NORMAL_DEPTH': TextureShaderResource('IN_NORMAL_DEPTH', self.t_normal_depth), 'IN_ID': TextureShaderResource('IN_ID', self.t_id), 'T_DEPTH': TextureShaderResource('', self.t_depth), #just pass the reference }) outputs['Scene'] = scene outputs['Normal Depth'] = self.t_normal_depth outputs['ID'] = self.t_id outputs.update(self.custom_targets)
def setup_render_targets(self, resolution): self.t_depth = Texture(resolution, GL_DEPTH_COMPONENT32F) self.t_main_color = Texture(resolution, GL_RGBA32F) self.fbo_main = RenderTarget([self.t_main_color], self.t_depth)
def setup_render_targets(self, resolution): super().setup_render_targets(resolution) self.t_postpro = Texture(resolution, GL_RGBA32F) self.fbo_postpro = RenderTarget([self.t_postpro])
def composite_line(self, max_width, pipeline, common_buffer, color, depth, id_texture, line_color, line_data): ''' if self.t_a is None or self.t_a.resolution != color.resolution: self.t_a = Texture(color.resolution, GL_RGBA32F) self.fbo_a = RenderTarget([self.t_a]) self.t_b = Texture(color.resolution, GL_RGBA32F) self.fbo_b = RenderTarget([self.t_b]) if self.shader is None: self.shader = pipeline.compile_shader_from_source(_shader_src) self.cleanup_shader = pipeline.compile_shader_from_source(_line_cleanup_src) #CLEANUP LINE #(Try to workaround numerical stability issues, disabled for now) cleanup = False if cleanup: self.fbo_composite.clear([(0,0,0,0)]) self.cleanup_shader.textures['line_data_texture'] = line_data self.cleanup_shader.bind() common_buffer.bind(self.cleanup_shader.uniform_blocks['COMMON_UNIFORMS']) pipeline.draw_screen_pass(self.cleanup_shader, self.fbo_composite) line_data = self.fbo_composite.targets[0] #JUMP FLOOD #Disabled since we moved back to brute-force line rendering jump_flood = False if jump_flood: jump_flood_max_width = max(line_data.resolution[0], line_data.resolution[1]) steps = [] width = 1 while width < jump_flood_max_width: steps.append(width) width*=2 steps.reverse() self.fbo_a.clear([(-1,-1,-1,-1)]) self.fbo_b.clear([(-1,-1,-1,-1)]) read = line_data write = self.fbo_b for i, step in enumerate(steps): if i > 0: if i % 2 == 0: read = self.t_a write = self.fbo_b else: read = self.t_b write = self.fbo_a self.shader.textures['input_texture'] = read self.shader.uniforms['width'].set_value(step) self.shader.bind() common_buffer.bind(self.shader.uniform_blocks['COMMON_UNIFORMS']) pipeline.draw_screen_pass(self.shader, write) ''' if self.t_composite is None or self.t_composite.resolution != color.resolution: self.t_composite = Texture(color.resolution, GL_RGBA32F) self.fbo_composite = RenderTarget([self.t_composite]) if self.composite_shader is None: global _LINE_COMPOSITE_SHADER if _LINE_COMPOSITE_SHADER is None: _LINE_COMPOSITE_SHADER = pipeline.compile_shader_from_source( _line_composite_src) self.composite_shader = _LINE_COMPOSITE_SHADER #LINE COMPOSITE self.fbo_composite.clear([(0, 0, 0, 0)]) self.composite_shader.uniforms['brute_force_range'].set_value( math.ceil(max_width / 2)) self.composite_shader.textures['color_texture'] = color self.composite_shader.textures['depth_texture'] = depth self.composite_shader.textures['id_texture'] = id_texture self.composite_shader.textures['line_color_texture'] = line_color self.composite_shader.textures['line_data_texture'] = line_data #self.composite_shader.textures['line_distance_field_texture'] = write.targets[0] self.composite_shader.bind() common_buffer.bind( self.composite_shader.uniform_blocks['COMMON_UNIFORMS']) pipeline.draw_screen_pass(self.composite_shader, self.fbo_composite) return self.t_composite