From f2d504006ec97c7d84e8059c48f5a37e005ece5f Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 17 Mar 2022 10:46:50 +0200 Subject: [PATCH] Remove support for material atlases from the Blender exporter Support for PBR materials was never added and it's unknown if it even works anymore. Baking and vertex colors are better solutions. --- blender/io_mspgl/export.py | 12 ++---- blender/io_mspgl/export_material.py | 39 ----------------- blender/io_mspgl/export_object.py | 35 +++------------ blender/io_mspgl/export_scene.py | 2 +- blender/io_mspgl/material.py | 67 ----------------------------- blender/io_mspgl/mesh.py | 37 +++------------- blender/io_mspgl/properties.py | 3 -- 7 files changed, 15 insertions(+), 180 deletions(-) diff --git a/blender/io_mspgl/export.py b/blender/io_mspgl/export.py index b74fa530..95cc556f 100644 --- a/blender/io_mspgl/export.py +++ b/blender/io_mspgl/export.py @@ -5,10 +5,9 @@ class DataExporter: objects = context.context.selected_objects resources = {} - material_atlases = {} task = ctx.task("Exporting resources", 1.0) - dummy_res = self.export_resources(task, objects, resources, material_atlases) + dummy_res = self.export_resources(task, objects, resources) path, base = os.path.split(out_fn) base, ext = os.path.splitext(base) @@ -32,10 +31,7 @@ class DataExporter: for r in refs: r.write_to_file(os.path.join(path, r.name)) - def export_resources(self, ctx, objects, resources, material_atlases): - if material_atlases is None: - material_atlases = {} - + def export_resources(self, ctx, objects, resources): object_exporter = None camera_exporter = None armature_exporter = None @@ -55,7 +51,7 @@ class DataExporter: if not object_exporter: from .export_object import ObjectExporter object_exporter = ObjectExporter() - object_exporter.export_object_resources(task, obj, resources, material_atlases) + object_exporter.export_object_resources(task, obj, resources) res = object_exporter.export_object(obj, resources) elif obj.type=='CAMERA': res_name = obj.name+".camera" @@ -132,7 +128,7 @@ class ProjectExporter: task = ctx.task("Exporting resources", 1.0) resources = {} - dummy_res = data_exporter.export_resources(task, all_objects, resources, None) + dummy_res = data_exporter.export_resources(task, all_objects, resources) task = ctx.task("Exporting scenes", 1.0) for s in ordered_scenes: diff --git a/blender/io_mspgl/export_material.py b/blender/io_mspgl/export_material.py index aceb6cc0..7f36beeb 100644 --- a/blender/io_mspgl/export_material.py +++ b/blender/io_mspgl/export_material.py @@ -181,42 +181,3 @@ class MaterialExporter: shader_res.statements.append(st) return shader_res - - -class MaterialAtlasExporter: - def __init__(self): - pass - - def export_technique_resources(self, material_atlas, resources): - from .datafile import Resource, Statement, Token - base_color_name = material_atlas.name+"_base_color.tex" - base_color_res = resources.get(base_color_name) - if not base_color_res: - base_color_res = Resource(base_color_name, "texture") - - base_color_res.statements.append(Statement("type", Token("\\2d"))) - base_color_res.statements.append(Statement("storage", Token('SRGB_ALPHA'), *material_atlas.size)) - base_color_res.statements.append(Statement("raw_data", material_atlas.base_color_data)) - - resources[base_color_name] = base_color_res - - sampler_name = "nearest.samp" - sampler_res = resources.get(sampler_name) - if not sampler_res: - sampler_res = Resource(sampler_name, "sampler") - - sampler_res.statements.append(Statement("filter", Token('NEAREST'))) - - resources[sampler_name] = sampler_res - - mat_name = material_atlas.name+".mat" - if mat_name not in resources: - mat_res = Resource(mat_name, "material") - mat_res.statements.append(Statement("type", Token('pbr'))) - mat_res.statements.append(mat_res.create_reference_statement("base_color_map", base_color_res)) - mat_res.statements.append(mat_res.create_reference_statement("sampler", sampler_res)) - - resources[mat_name] = mat_res - - def export_technique(self, material_atlas, resources): - return create_technique_resource(material_atlas, resources) diff --git a/blender/io_mspgl/export_object.py b/blender/io_mspgl/export_object.py index 476927af..989d6758 100644 --- a/blender/io_mspgl/export_object.py +++ b/blender/io_mspgl/export_object.py @@ -10,45 +10,22 @@ class ObjectExporter: return lods - def export_object_resources(self, ctx, obj, resources, material_atlases): - if material_atlases is None: - material_atlases = {} - + def export_object_resources(self, ctx, obj, resources): lods = self.collect_object_lods(obj) from .export_mesh import MeshExporter - from .export_material import MaterialAtlasExporter, MaterialExporter + from .export_material import MaterialExporter from .mesh import create_mesh_from_object - from .material import Material, create_material_atlas + from .material import Material mesh_export = MeshExporter() material_export = MaterialExporter() - material_atlas_export = MaterialAtlasExporter() ctx.set_slices(len(lods)) for l in lods: lod_index = l.lod_index if l.lod_for_parent else 0 task = ctx.next_slice("LOD {}".format(lod_index)) - material_atlas = None - atlas_flags = [m.render_mode!='EXTERNAL' and m.material_atlas for m in l.data.materials if m] - if any(atlas_flags): - mmk = lambda m: m.shader if m.render_mode=='CUSTOM' else "" - material_atlas_key = mmk(l.data.materials[0]) - key_mismatch = any(mmk(m)!=material_atlas_key for m in l.data.materials) - if not all(atlas_flags) or key_mismatch: - raise Exception("Invalid configuration on object {}: Mixed material atlas state") - - if material_atlas_key in material_atlases: - material_atlas = material_atlases[material_atlas_key] - else: - material_atlas = create_material_atlas(task.context, l.data.materials[0]) - material_atlases[material_atlas_key] = material_atlas - - tech_name = "{}.tech".format(material_atlas.name) - if tech_name not in resources: - material_atlas_export.export_technique_resources(material_atlas, resources) - resources[tech_name] = material_atlas_export.export_technique(material_atlas, resources) - elif l.material_slots and l.material_slots[0].material: + if l.material_slots and l.material_slots[0].material: material = l.material_slots[0].material subtask = task.task(material, 0.1) if material.render_mode!='EXTERNAL': @@ -63,7 +40,7 @@ class ObjectExporter: mesh_name = l.data.name+".mesh" if mesh_name not in resources: subtask = task.task(l.data, 1.0) - mesh = create_mesh_from_object(subtask, l, material_atlas) + mesh = create_mesh_from_object(subtask, l) mesh_res = mesh_export.export_mesh(subtask, mesh) resources[mesh_name] = mesh_res @@ -98,8 +75,6 @@ class ObjectExporter: if material: if material.render_mode=='EXTERNAL': tech_name = material.technique - elif material.material_atlas: - tech_name = "material_atlas_{}.tech".format(os.path.splitext(material.technique)[0]) else: tech_name = material.name+".tech" else: diff --git a/blender/io_mspgl/export_scene.py b/blender/io_mspgl/export_scene.py index 861286ff..e7759e9c 100644 --- a/blender/io_mspgl/export_scene.py +++ b/blender/io_mspgl/export_scene.py @@ -33,7 +33,7 @@ class SceneExporter: from .export import DataExporter data_exporter = DataExporter() - data_exporter.export_resources(ctx, scene.prototypes, resources, None) + data_exporter.export_resources(ctx, scene.prototypes, resources) def export_scene(self, scene, resources): from .datafile import Resource, Statement, Token diff --git a/blender/io_mspgl/material.py b/blender/io_mspgl/material.py index e92aee2f..ff145515 100644 --- a/blender/io_mspgl/material.py +++ b/blender/io_mspgl/material.py @@ -296,70 +296,3 @@ class Material: prop = MaterialProperty(*args) self.properties.append(prop) return prop - - -class MaterialAtlas: - def __init__(self, materials): - self.render_mode = materials[0].render_mode - if self.render_mode=='EXTERNAL': - raise Exception("Material atlas with external render mode does not make sense") - - if self.render_mode=='CUSTOM': - self.render_methods = materials[0].render_methods - else: - self.render_methods = None - if self.render_methods: - self.name = "material_atlas_"+os.path.splitext(self.render_methods[0].shader)[0] - else: - self.name = "material_atlas" - self.receive_shadows = materials[0].receive_shadows - self.cast_shadows = (materials[0].shadow_method!='NONE') - self.materials = materials - self.material_names = [m.name for m in self.materials] - self.uniforms = None - method_hash = compute_render_method_hash(self) - for m in self.materials: - if m.render_mode!=self.render_mode: - raise Exception("Conflicting render modes in MaterialAtlas constructor") - if self.render_mode=='CUSTOM' and compute_render_method_hash(m)!=method_hash: - raise Exception("Conflicting shaders in MaterialAtlas constructor") - if m.receive_shadows!=self.receive_shadows or m.shadow_method!=materials[0].shadow_method: - raise Exception("Conflicting shadow settings in MaterialAtlas constructor") - - count = len(self.materials) - size = 1 - while size*size*2=count: - self.size = (size, size) - else: - self.size = (size*2, size) - - from .util import get_colormap - - cm = get_colormap(True) - self.base_color_data = "" - for m in map(Material, self.materials): - if any(p.texture for p in m.properties): - raise Exception("Texturing is incompatible with material atlas") - base_color = [int(cm(c)*255) for c in m.base_color.value] - self.base_color_data += "\\x{:02X}\\x{:02X}\\x{:02X}\\xFF".format(*base_color) - self.base_color_data += "\\x00\\x00\\x00\\x00"*(self.size[0]*self.size[1]-count) - - def get_material_uv(self, material): - index = self.material_names.index(material.name) - x = index%self.size[0] - y = index//self.size[0] - return ((x+0.5)/self.size[0], (y+0.5)/self.size[1]) - -def create_material_atlas(context, material): - if not material.material_atlas: - raise Exception("Material is not part of a material atlas") - - method_hash = compute_render_method_hash(material) - materials = [] - for m in context.blend_data.materials: - if m.material_atlas and compute_render_method_hash(m)==method_hash: - materials.append(m) - - return MaterialAtlas(materials) diff --git a/blender/io_mspgl/mesh.py b/blender/io_mspgl/mesh.py index 3b1c74df..bf5d108b 100644 --- a/blender/io_mspgl/mesh.py +++ b/blender/io_mspgl/mesh.py @@ -257,12 +257,12 @@ class Mesh: # Merge materials and form a lookup from source material indices to the # merged material list - material_atlas = [] + material_lookup = [] for m in other.materials: if m in self.materials: - material_atlas.append(self.materials.index(m)) + material_lookup.append(self.materials.index(m)) else: - material_atlas.append(len(self.materials)) + material_lookup.append(len(self.materials)) self.materials.append(m) # Append data and adjust indices where necessary. Since the data is @@ -293,7 +293,7 @@ class Mesh: f.index += offset f.loop_indices = range(f.loop_indices.start+offset, f.loop_indices.stop+offset) if other.materials: - f.material_index = material_atlas[f.material_index] + f.material_index = material_lookup[f.material_index] offset = len(self.edges) self.edges += other.edges @@ -411,30 +411,6 @@ class Mesh: for g in v.groups: g.group = group_index_map[g.group] - def apply_material_atlas(self, material_atlas): - for m in self.materials: - if m.name not in material_atlas.material_names: - raise Exception("Material atlas {} is not compatible with Mesh {}".format(material_atlas.name, self.name)) - - if self.use_uv=='NONE': - return - - layer = UvLayer("material_atlas") - if self.use_uv=='UNIT0': - self.uv_layers = [layer] - layer.unit = 0 - else: - self.uv_layers.append(layer) - used_units = [u.unit for u in self.uv_layers] - layer.unit = next(i for i in itertools.count() if i not in used_units) - self.uv_layers.sort(key=lambda u: u.unit) - - layer.uvs = [(0.0, 0.0)]*len(self.loops) - for f in self.faces: - uv = material_atlas.get_material_uv(self.materials[f.material_index]) - for i in f.loop_indices: - layer.uvs[i] = uv - def prepare_uv(self, task): # Form a list of UV layers referenced by materials with the array atlas # property set @@ -793,7 +769,7 @@ class Mesh: e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index) -def create_mesh_from_object(ctx, obj, material_atlas): +def create_mesh_from_object(ctx, obj): if obj.type!="MESH": raise Exception("Object {} is not a mesh".format(obj.name)) @@ -838,9 +814,6 @@ def create_mesh_from_object(ctx, obj, material_atlas): mesh.name = obj.data.name - if material_atlas: - mesh.apply_material_atlas(material_atlas) - task = ctx.task("Triangulating", 0.3) mesh.prepare_triangles(task) task = ctx.task("Smoothing", 0.5) diff --git a/blender/io_mspgl/properties.py b/blender/io_mspgl/properties.py index 9b00a76c..a5a24274 100644 --- a/blender/io_mspgl/properties.py +++ b/blender/io_mspgl/properties.py @@ -119,8 +119,6 @@ class MspGLMaterialProperties(bpy.types.Panel): self.layout.prop(mat, "array_atlas") if mat.array_atlas: self.layout.prop(mat, "array_layer") - if mat.render_mode!='EXTERNAL': - self.layout.prop(mat, "material_atlas") if mat.render_mode=='CUSTOM': self.layout.separator() self.layout.label(text="Uniform values") @@ -272,7 +270,6 @@ def register_properties(): bpy.types.Material.image_based_lighting = bpy.props.BoolProperty(name="Image based lighting", description="Use an environment map for ambient lighting", default=False) bpy.types.Material.array_atlas = bpy.props.BoolProperty(name="Texture array atlas", description="The material is stored in a texture array") bpy.types.Material.array_layer = bpy.props.IntProperty("Texture array layer", description="Layer of the texture array atlas to use") - bpy.types.Material.material_atlas = bpy.props.BoolProperty(name="Material atlas", description="Make this material part of a material atlas") bpy.types.Material.uniforms = bpy.props.CollectionProperty(type=MspGLUniform, name="Uniforms", description="Uniform variables to add to the technique") bpy.types.Material.active_uniform_index = bpy.props.IntProperty("Active uniform index") -- 2.43.0