def reflect_outputs(cls): return { 'A' : Parameter('', Type.TEXTURE), 'B' : Parameter('', Type.TEXTURE), 'C' : Parameter('', Type.TEXTURE), 'D' : Parameter('', Type.TEXTURE), }
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 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'
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
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)
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': '' }})
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] = {}
def reflect_inputs(cls): inputs = {} inputs['Color'] = Parameter('', Type.TEXTURE) return inputs
def reflect_outputs(cls): outputs = {} outputs['Scene'] = Parameter('Scene', Type.OTHER) return outputs
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
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()
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()
def reflect_inputs(cls): return { 'Output Name' : Parameter('', Type.STRING) }
def reflect_outputs(cls): return { 'Opaque Layer' : Parameter('', Type.TEXTURE) }
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()
def reflect_outputs(cls): outputs = {} outputs['Color'] = Parameter('', Type.TEXTURE) return outputs
def reflect_inputs(cls): return { 'Packed Texture' : Parameter('usampler2D', Type.OTHER) }
def reflect_inputs(cls): inputs = {} inputs['Scene'] = Parameter('Scene', Type.OTHER) return inputs
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
def reflect_outputs(cls): outputs = {} outputs['Scene'] = Parameter('Scene', Type.OTHER) outputs['Normal Depth'] = Parameter('', Type.TEXTURE) outputs['ID'] = Parameter('', Type.TEXTURE) return outputs