Beispiel #1
0
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
Beispiel #2
0
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 }
Beispiel #3
0
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]
Beispiel #4
0
class ScreenPass(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 'Screen.SCREEN_SHADER'
    
    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']]
Beispiel #5
0
    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
Beispiel #6
0
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)
Beispiel #7
0
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
Beispiel #9
0
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)
Beispiel #10
0
class ScreenPass(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 'Screen.SCREEN_SHADER'
    
    @classmethod
    def reflect_inputs(cls):
        inputs = {}
        inputs['Layer Only'] = Parameter(True, Type.BOOL)
        inputs['Scene'] = Parameter('Scene', Type.OTHER)
        inputs['Normal Depth'] = Parameter('', Type.TEXTURE)
        inputs['ID'] = Parameter('', Type.TEXTURE)
        return inputs
    
    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']]
Beispiel #11
0
class LineRendering(object):
    def __init__(self):
        '''
        self.t_a = None
        self.t_b = None
        self.fbo_a = None
        self.fbo_b = None
        self.shader = None
        self.cleanup_shader = None
        '''
        self.t_composite = None
        self.fbo_composite = None
        self.composite_shader = None

    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