Example #1
0
 def reflect_outputs(cls):
     return {
         'A' : Parameter('', Type.TEXTURE),
         'B' : Parameter('', Type.TEXTURE),
         'C' : Parameter('', Type.TEXTURE),
         'D' : Parameter('', Type.TEXTURE),
     }
Example #2
0
 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
Example #3
0
 def setup_shape(self):
     from Malt.PipelineParameters import Parameter
     base_type = True
     try:
         Parameter.from_glsl_type(self.data_type)
     except:
         base_type = False
     array_type = self.array_size > 0
     if base_type:
         if array_type:
             self.display_shape = 'CIRCLE_DOT'
         else:
             self.display_shape = 'CIRCLE'
     else:
         if array_type:
             self.display_shape = 'SQUARE_DOT'
         else:
             self.display_shape = 'SQUARE'
Example #4
0
 def reflect_inputs(cls):
     inputs = {}
     inputs['Color'] = Parameter('', Type.TEXTURE)
     inputs['Line Color'] = Parameter('', Type.TEXTURE)
     inputs['Line Width'] = Parameter('', Type.TEXTURE)
     inputs['Max Width'] = Parameter(10, Type.INT)
     inputs['Line Scale'] = Parameter(1.0, Type.FLOAT)
     inputs['Normal Depth'] = Parameter('', Type.TEXTURE)
     inputs['ID'] = Parameter('', Type.TEXTURE)
     return inputs
Example #5
0
 def add_override(self, property_name, override_name):
     main_prop = self.get_rna()[property_name]
     new_name = property_name + ' @ ' + override_name
     property = {}
     if main_prop['type'] == Type.MATERIAL:
         property[new_name] = MaterialParameter(
             main_prop['default'], self.materials[property_name].extension)
     else:
         property[new_name] = Parameter(main_prop['default'],
                                        main_prop['type'],
                                        main_prop['size'],
                                        main_prop['filter'],
                                        main_prop['malt_subtype'])
     self.setup(property, replace_parameters=False)
Example #6
0
 def malt_setup(self):
     if self.first_setup:
         self.name = 'Array Index'
     self.setup_sockets(
         {
             'array': {
                 'type': '',
                 'size': 1
             },
             'index': {
                 'type': Parameter(0, Type.INT)
             }
         }, {'element': {
             'type': ''
         }})
Example #7
0
 def __init__(self, path, pipeline, search_paths=[], custom_passes={}):
     self.path = path
     self.parameters = {}
     self.compiler_error = ''
     
     compiled_material = pipeline.compile_material(path, search_paths)#, custom_passes)
     
     if isinstance(compiled_material, str):
         self.compiler_error = compiled_material
     else:
         for pass_name, shader in compiled_material.items():
             for uniform_name, uniform in shader.uniforms.items():
                 self.parameters[uniform_name] = Parameter.from_uniform(uniform)
             if shader.error:
                 self.compiler_error += pass_name + " : " + shader.error
             if shader.validator:
                 self.compiler_error += pass_name + " : " + shader.validator
     
     if self.compiler_error == '':
         global MATERIAL_SHADERS
         MATERIAL_SHADERS[self.path] = compiled_material
     else:
         MATERIAL_SHADERS[self.path] = {}
Example #8
0
 def reflect_inputs(cls):
     inputs = {}
     inputs['Color'] = Parameter('', Type.TEXTURE)
     return inputs
Example #9
0
 def reflect_outputs(cls):
     outputs = {}
     outputs['Scene'] = Parameter('Scene', Type.OTHER)
     return outputs
Example #10
0
 def reflect_inputs(cls):
     inputs = {}
     inputs['Scene'] = Parameter('Scene', Type.OTHER)
     inputs['Point Resolution'] = Parameter(2048, Type.INT)
     inputs['Point Resolution @ Preview'] = Parameter(512, Type.INT)
     inputs['Spot Resolution'] = Parameter(2048, Type.INT)
     inputs['Spot Resolution @ Preview'] = Parameter(512, Type.INT)
     inputs['Sun Resolution'] = Parameter(2048, Type.INT)
     inputs['Sun Max Distance'] = Parameter(100, Type.FLOAT)
     inputs['Sun Max Distance @ Preview'] = Parameter(25, Type.FLOAT)
     inputs['Sun CSM Count'] = Parameter(4, Type.INT)
     inputs['Sun CSM Count @ Preview'] = Parameter(2, Type.INT)
     inputs['Sun CSM Distribution'] = Parameter(0.9, Type.FLOAT)
     return inputs
Example #11
0
    def setup(self,
              parameters,
              replace_parameters=True,
              reset_to_defaults=False,
              skip_private=True):
        rna = self.get_rna()

        def setup_parameter(name, parameter):
            if name not in rna.keys():
                rna[name] = {}

            type_changed = 'type' not in rna[name].keys(
            ) or rna[name]['type'] != parameter.type
            size_changed = 'size' in rna[name].keys(
            ) and rna[name]['size'] != parameter.size

            if reset_to_defaults:
                #TODO: Rename
                type_changed = True

            def to_basic_type(value):
                try:
                    return tuple(value)
                except:
                    return value

            def equals(a, b):
                return to_basic_type(a) == to_basic_type(b)

            def resize():
                if parameter.size == 1:
                    self[name] = self[name][0]
                else:
                    if rna[name]['size'] > parameter.size:
                        self[name] = self[name][:parameter.size]
                    else:
                        first = self[name]
                        try:
                            first = list(first)
                        except:
                            first = [first]
                        second = list(parameter.default_value)
                        self[name] = first + second[rna[name]['size']:]

            if parameter.type in (Type.INT, Type.FLOAT):
                if type_changed or equals(rna[name]['default'], self[name]):
                    self[name] = parameter.default_value
                elif size_changed:
                    resize()

            if parameter.type == Type.STRING:
                if type_changed or equals(rna[name]['default'], self[name]):
                    self[name] = parameter.default_value

            if parameter.type == Type.BOOL:
                if name not in self.bools:
                    self.bools.add().name = name
                if type_changed or equals(rna[name]['default'],
                                          self.bools[name].boolean):
                    self.bools[name].boolean = parameter.default_value
                elif size_changed:
                    resize()

            if parameter.type == Type.TEXTURE:
                if name not in self.textures:
                    self.textures.add().name = name
                if type_changed or self.textures[name] == rna[name]['default']:
                    if isinstance(parameter.default_value, bpy.types.Image):
                        self.textures.texture = parameter.default_value

            if parameter.type == Type.GRADIENT:
                if name not in self.gradients:
                    self.gradients.add().name = name
                    # Load gradient from material nodes (backward compatibility)
                    if isinstance(self.id_data, bpy.types.Material):
                        material = self.id_data
                        if material.use_nodes and name in material.node_tree.nodes:
                            self.gradients[
                                name].texture = bpy.data.textures.new(
                                    'malt_color_ramp', 'BLEND')
                            self.gradients[name].texture.use_color_ramp = True
                            old = material.node_tree.nodes[name].color_ramp
                            new = self.gradients[name].texture.color_ramp
                            MaltTextures.copy_color_ramp(old, new)
                            self.gradients[name].texture.update_tag()
                if type_changed or self.gradients[name] == rna[name]['default']:
                    if isinstance(parameter.default_value, bpy.types.Texture):
                        self.gradients.texture = parameter.default_value

            if parameter.type == Type.MATERIAL:
                if name not in self.materials:
                    self.materials.add().name = name

                self.materials[name].extension = parameter.extension
                shader_path = parameter.default_value
                if shader_path and shader_path != '':
                    if isinstance(shader_path, str):
                        material_name = name + ' : ' + os.path.basename(
                            shader_path)
                        if material_name not in bpy.data.materials:
                            bpy.data.materials.new(material_name)
                            material = bpy.data.materials[material_name]
                            material.malt.shader_source = shader_path
                        material = self.materials[name].material
                        if type_changed or (material and rna[name]['default']
                                            == material.malt.shader_source):
                            self.materials[name].material = bpy.data.materials[
                                material_name]

                    if isinstance(shader_path, tuple):
                        blend_path, material_name = parameter.default_value
                        blend_path += '.blend'
                        if material_name not in bpy.data.materials:
                            internal_dir = 'Material'
                            bpy.ops.wm.append(
                                filepath=os.path.join(blend_path, internal_dir,
                                                      material_name),
                                directory=os.path.join(blend_path,
                                                       internal_dir),
                                filename=material_name)
                        if type_changed:
                            self.materials[name].material = bpy.data.materials[
                                material_name]

            if parameter.type == Type.GRAPH:
                if name not in self.graphs:
                    self.graphs.add().name = name
                self.graphs[name].type = parameter.graph_type
                if parameter.default_value and isinstance(
                        parameter.default_value, tuple):
                    blend_path, tree_name = parameter.default_value
                    blend_path += '.blend'
                    if tree_name not in bpy.data.node_groups:
                        internal_dir = 'NodeTree'
                        bpy.ops.wm.append(
                            filepath=os.path.join(blend_path, internal_dir,
                                                  tree_name),
                            directory=os.path.join(blend_path, internal_dir),
                            filename=tree_name)
                    if type_changed:
                        self.graphs[name].graph = bpy.data.node_groups[
                            tree_name]
                    if self.graphs[name].graph is not None:
                        assert (parameter.graph_type ==
                                self.graphs[name].graph.graph_type)

            if name not in self.override_from_parents:
                self.override_from_parents.add().name = name

            rna[name]['active'] = True
            rna[name]["default"] = parameter.default_value
            rna[name]['type'] = parameter.type
            rna[name]['malt_subtype'] = parameter.subtype
            rna[name]['size'] = parameter.size
            rna[name]['filter'] = parameter.filter

        #TODO: We should purge non active properties (specially textures)
        # at some point, likely on file save or load
        # so we don't lose them immediately when changing shaders/pipelines
        if replace_parameters:
            for key, value in rna.items():
                if '@' not in key:
                    rna[key]['active'] = False

        for name, parameter in parameters.items():
            if skip_private and (name.isupper() or name.startswith('_')):
                # We treat underscored and all caps uniforms as "private"
                continue
            setup_parameter(name, parameter)

        for key, value in rna.items():
            if '@' in key and key not in parameters.keys():
                main_name = key.split(' @ ')[0]
                rna[key][
                    'active'] = rna[main_name]['active'] and rna[key]['active']
                if rna[key]['active']:
                    if rna[key]['type'] != rna[main_name]['type'] or rna[key][
                            'size'] != rna[main_name]['size']:
                        parameter = Parameter(rna[main_name]['default'],
                                              rna[main_name]['type'],
                                              rna[main_name]['size'],
                                              rna[main_name]['filter'],
                                              rna[main_name]['malt_subtype'])
                        setup_parameter(key, parameter)

        for key, value in rna.items():
            rna_prop = rna[key]
            if rna_prop['active'] == False:
                continue
            #Default to color since it's the most common use case
            malt_subtype = rna_prop.get('malt_subtype')
            if rna_prop['type'] == Type.FLOAT and rna_prop['size'] >= 3 and (
                    malt_subtype is None or malt_subtype == 'Color'):
                rna_prop['subtype'] = 'COLOR'
                rna_prop['use_soft_limits'] = True
                rna_prop['soft_min'] = 0.0
                rna_prop['soft_max'] = 1.0
            else:
                rna_prop['subtype'] = 'BLEND'
                rna_prop['use_soft_limits'] = False

            if bpy.app.version[0] >= 3:
                if rna_prop['type'] in (Type.FLOAT, Type.INT):
                    ui = self.id_properties_ui(key)
                    if rna_prop['subtype'] == 'COLOR':
                        ui.update(default=rna_prop['default'],
                                  subtype='COLOR',
                                  soft_min=0.0,
                                  soft_max=1.0)
                    else:
                        dic = ui.as_dict()
                        ui.update(default=rna_prop['default'],
                                  subtype='NONE',
                                  soft_min=dic['min'],
                                  soft_max=dic['max'])

        # Force a depsgraph update.
        # Otherwise these won't be available inside scene_eval
        self.id_data.update_tag()
        for screen in bpy.data.screens:
            for area in screen.areas:
                area.tag_redraw()
Example #12
0
    def update_pipeline(self, context):
        global _TIMESTAMP
        _TIMESTAMP = time.time()

        #TODO: Sync all scenes. Only one active pipeline per Blender instance is supported atm.
        pipeline = self.pipeline
        if pipeline == '':
            current_dir = os.path.dirname(os.path.abspath(__file__))
            default_pipeline = os.path.join(current_dir, '.MaltPath', 'Malt',
                                            'Pipelines', 'NPR_Pipeline',
                                            'NPR_Pipeline.py')
            if platform.system() == 'Darwin':
                # The NPR Pipeline doesn't work on OpenGL implementations limited to 16 sampler uniforms
                default_pipeline = os.path.join(current_dir, '.MaltPath',
                                                'Malt', 'Pipelines',
                                                'MiniPipeline',
                                                'MiniPipeline.py')
            pipeline = default_pipeline

        preferences = bpy.context.preferences.addons['BlenderMalt'].preferences

        debug_mode = bool(preferences.debug_mode)
        renderdoc_path = preferences.renderdoc_path
        plugin_dirs = []
        if os.path.exists(preferences.plugins_dir):
            plugin_dirs.append(preferences.plugins_dir)
        plugin_dir = bpy.path.abspath(self.plugins_dir,
                                      library=self.id_data.library)
        if os.path.exists(plugin_dir):
            plugin_dirs.append(plugin_dir)

        path = bpy.path.abspath(pipeline, library=self.id_data.library)
        import Bridge
        bridge = Bridge.Client_API.Bridge(path, int(self.viewport_bit_depth),
                                          debug_mode, renderdoc_path,
                                          plugin_dirs)
        from Malt.Utils import LOG
        LOG.info('Blender {} {} {}'.format(bpy.app.version_string,
                                           bpy.app.build_branch,
                                           bpy.app.build_hash))
        params = bridge.get_parameters()

        #BlenderMalt parameters
        from Malt.PipelineParameters import Parameter, Type
        params.world['Viewport.Resolution Scale'] = Parameter(1.0, Type.FLOAT)
        params.world['Viewport.Smooth Interpolation'] = Parameter(
            True, Type.BOOL)

        global _BRIDGE, _PIPELINE_PARAMETERS, _WORLD
        _BRIDGE = bridge
        _PIPELINE_PARAMETERS = params
        _WORLD = context.scene.world.name_full

        MaltMaterial.reset_materials()
        MaltMeshes.reset_meshes()
        MaltTextures.reset_textures()

        #TODO: This can fail depending on the current context, ID classes might not be writeable
        self.graph_types.clear()
        for graph in bridge.graphs.keys():
            self.graph_types.add().name = graph

        setup_all_ids()
Example #13
0
 def reflect_inputs(cls):
     return {
         'Output Name' : Parameter('', Type.STRING)
     }
Example #14
0
 def reflect_outputs(cls):
     return {
         'Opaque Layer' : Parameter('', Type.TEXTURE)
     }
Example #15
0
    def setup_sockets(self, inputs, outputs, expand_structs=True):
        def _expand_structs(sockets):
            result = {}
            for name, dic in sockets.items():
                result[name] = dic
                struct_type = self.id_data.get_struct_type(dic['type'])
                if struct_type:
                    for member in struct_type['members']:
                        result[f"{name}.{member['name']}"] = member
            return result
        if expand_structs:
            inputs = _expand_structs(inputs)
            outputs = _expand_structs(outputs)
        def setup(current, new):
            remove = []
            for e in current.keys():
                if e not in new:
                    remove.append(current[e])
            for e in remove:
                if len(e.links) == 0:
                    current.remove(e)
                else:
                    e.active = False
            socket_index = 0
            for i, (name, dic) in enumerate(new.items()):
                if '@' in name:
                    continue #Skip overrides
                type = dic['type']
                size = dic['size'] if 'size' in dic else 0
                if name not in current:
                    current.new('MaltSocket', name)
                if isinstance(type, Parameter):
                    current[name].data_type = type.type_string()
                    current[name].array_size = 0 #TODO
                else:
                    current[name].data_type = type
                    current[name].array_size = size
                current[name].active = True
                current[name].default_initialization = ''
                try:
                    default = dic['meta']['default']
                    if isinstance(default, str):
                        current[name].default_initialization = default
                except:
                    pass
                if current.find(name) != socket_index:
                    current.move(current.find(name), socket_index)
                socket_index += 1

        setup(self.inputs, inputs)
        setup(self.outputs, outputs)
        parameters = {}
        for name, input in inputs.items():
            parameter = None
            type = input['type']
            size = input['size'] if 'size' in input else 0
            try:
                subtype = input['meta']['subtype']
            except:
                subtype = None
            if isinstance(type, Parameter):
                parameter = type
            else:
                if size == 0:
                    try:
                        parameter = Parameter.from_glsl_type(type, subtype)
                    except:
                        parameter = Parameter(type, Type.OTHER)
                else:
                    parameter = Parameter(type, Type.OTHER)
                try:
                    default = input['meta']['default']
                    if isinstance(default, str) == False:
                        parameter.default_value = default
                except:
                    pass
            if parameter:
                parameters[name] = parameter
        self.malt_parameters.setup(parameters, skip_private=False)
        self.setup_socket_shapes()
        if self.first_setup:
            self.setup_width()
Example #16
0
 def reflect_outputs(cls):
     outputs = {}
     outputs['Color'] = Parameter('', Type.TEXTURE)
     return outputs
Example #17
0
 def reflect_inputs(cls):
     return {
         'Packed Texture' : Parameter('usampler2D', Type.OTHER)
     }
Example #18
0
File: PrePass.py Project: bnpr/Malt
 def reflect_inputs(cls):
     inputs = {}
     inputs['Scene'] = Parameter('Scene', Type.OTHER)
     return inputs
Example #19
0
 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
Example #20
0
File: PrePass.py Project: bnpr/Malt
 def reflect_outputs(cls):
     outputs = {}
     outputs['Scene'] = Parameter('Scene', Type.OTHER)
     outputs['Normal Depth'] = Parameter('', Type.TEXTURE)
     outputs['ID'] = Parameter('', Type.TEXTURE)
     return outputs