From 4291fcf9489087492085b70e7960bdb3dbb5dc9c Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 17 Mar 2022 22:08:13 +0200 Subject: [PATCH] Make it possible to export instance arrays from Blender --- blender/io_mspgl/export_material.py | 53 ++++++++++++++++++++++------- blender/io_mspgl/export_scene.py | 18 ++++++++++ blender/io_mspgl/material.py | 1 + blender/io_mspgl/properties.py | 2 ++ blender/io_mspgl/scene.py | 2 ++ 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/blender/io_mspgl/export_material.py b/blender/io_mspgl/export_material.py index f01745b9..64d11b86 100644 --- a/blender/io_mspgl/export_material.py +++ b/blender/io_mspgl/export_material.py @@ -30,11 +30,13 @@ class MaterialExporter: else: resources[mat_name] = None - if material.cast_shadows and material.alpha_cutoff>0.0: - for detail in ("", "_thsm"): - shader_name = "occluder{}_masked.shader".format(detail) + for thsm in (False, True): + occluder_variant, occluder_spec_values = self.get_occluder_shader_variant(material, thsm) + if occluder_spec_values: + base_variant = "_thsm" if thsm else "" + shader_name = "occluder{}.shader".format(occluder_variant) if shader_name not in resources: - resources[shader_name] = self.export_shader(shader_name, "occluder{}.glsl".format(detail), {"use_alpha_cutoff":True}, resources) + resources[shader_name] = self.export_shader(shader_name, "occluder{}.glsl".format(base_variant), occluder_spec_values, resources) def export_technique(self, material, resources): from .material import Material @@ -90,25 +92,34 @@ class MaterialExporter: st.sub.append(Statement("receive_shadows", True)) if material.image_based_lighting: st.sub.append(Statement("image_based_lighting", True)) + if material.instancing: + st.sub.append(Statement("instancing", True)) if material.face_cull=='BACK': st.sub.append(Statement("face_cull", Token("CULL_BACK"))) tech_res.statements.append(st) if material.cast_shadows: - tech_res.statements.append(self.create_shadow_method(tech_res, material, resources, "")); - tech_res.statements.append(self.create_shadow_method(tech_res, material, resources, "_thsm")); + tech_res.statements.append(self.create_shadow_method(tech_res, material, resources, False)); + tech_res.statements.append(self.create_shadow_method(tech_res, material, resources, True)); return tech_res - def create_shadow_method(self, tech_res, material, resources, detail): + def create_shadow_method(self, tech_res, material, resources, thsm): from .datafile import Statement, Token - color_prop = next((p for p in material.properties if p.keyword and "color" in p.keyword), None) + occluder_variant, occluder_spec_values = self.get_occluder_shader_variant(material, thsm) + + shader_stem = "occluder{}.shader" if occluder_spec_values else "occluder{}.glsl.shader" + shader_name = shader_stem.format(occluder_variant) - st = Statement("method", "shadow"+detail) - if material.alpha_cutoff>0.0 and color_prop and 'A' in color_prop.tex_channels: - st.sub.append(tech_res.create_reference_statement("shader", resources["occluder{}_masked.shader".format(detail)])) + st = Statement("method", "shadow"+("_thsm" if thsm else "")) + if occluder_spec_values: + st.sub.append(tech_res.create_reference_statement("shader", resources[shader_name])) + else: + st.sub.append(Statement("shader", shader_name)) + + if occluder_spec_values.get("use_alpha_cutoff"): ss = Statement("texture", "alpha_map") from .export_texture import TextureExporter @@ -116,6 +127,7 @@ class MaterialExporter: texture_export = TextureExporter() sampler_export = SamplerExporter() + color_prop = material.properties[0] tex_res = resources[texture_export.get_texture_name(color_prop.texture, color_prop.tex_channels)] ss.sub.append(tech_res.create_reference_statement("texture", tex_res)) ss.sub.append(tech_res.create_reference_statement("sampler", resources[sampler_export.get_sampler_name(color_prop.texture)])) @@ -124,14 +136,29 @@ class MaterialExporter: ss = Statement("uniforms") ss.sub.append(Statement("uniform", "alpha_cutoff", material.alpha_cutoff)) st.sub.append(ss) - else: - st.sub.append(Statement("shader", "occluder{}.glsl.shader".format(detail))) if material.face_cull=='BACK': st.sub.append(Statement("face_cull", Token("CULL_BACK"))) return st; + def get_occluder_shader_variant(self, material, thsm): + variant = "" + if thsm: + variant += "_thsm" + + spec_values = {} + + color_prop = material.properties[0] + if material.cast_shadows and material.alpha_cutoff>0.0: + spec_values["use_alpha_cutoff"] = True + variant += "_masked" + if material.instancing: + spec_values["use_instancing"] = True + variant += "_instanced" + + return (variant, spec_values) + def export_material(self, material, resources): from .datafile import Resource, Statement, Token mat_res = Resource(material.name+".mat", "material") diff --git a/blender/io_mspgl/export_scene.py b/blender/io_mspgl/export_scene.py index a42d8180..4f983977 100644 --- a/blender/io_mspgl/export_scene.py +++ b/blender/io_mspgl/export_scene.py @@ -67,7 +67,14 @@ class SceneExporter: def add_instances(self, scene_res, statements, instances, resources): from .datafile import Statement + array_prototypes = [] + for i in instances: + if i.prototype.use_array: + if i.prototype not in array_prototypes: + array_prototypes.append(i.prototype) + continue + obj_res = resources[i.prototype.name+".object"] st = scene_res.create_reference_statement("object", obj_res) if i.name: @@ -76,6 +83,17 @@ class SceneExporter: st.sub.append(self.create_transform_statement(i)) statements.append(st) + for p in array_prototypes: + obj_res = resources[p.name+".object"] + st = scene_res.create_reference_statement("array", obj_res) + + for i in p.instances: + ss = Statement("instance") + ss.sub.append(self.create_transform_statement(i)) + st.sub.append(ss) + + statements.append(st) + def create_transform_statement(self, instance): from .datafile import Statement diff --git a/blender/io_mspgl/material.py b/blender/io_mspgl/material.py index ff145515..ccbf0083 100644 --- a/blender/io_mspgl/material.py +++ b/blender/io_mspgl/material.py @@ -225,6 +225,7 @@ class Material: self.blend_type = 'ALPHA' if material.blend_method=='BLEND' else 'NONE' self.alpha_cutoff = material.alpha_threshold if material.blend_method=='CLIP' else 0.0 self.image_based_lighting = material.image_based_lighting + self.instancing = material.instancing if self.render_mode=='EXTERNAL' and not self.technique: raise Exception("Invalid configuration on material {}: No technique for external rendering".format(self.name)) diff --git a/blender/io_mspgl/properties.py b/blender/io_mspgl/properties.py index a5a24274..b21f45a2 100644 --- a/blender/io_mspgl/properties.py +++ b/blender/io_mspgl/properties.py @@ -116,6 +116,7 @@ class MspGLMaterialProperties(bpy.types.Panel): if mat.render_mode=='BUILTIN': self.layout.prop(mat, "receive_shadows") self.layout.prop(mat, "image_based_lighting") + self.layout.prop(mat, "instancing") self.layout.prop(mat, "array_atlas") if mat.array_atlas: self.layout.prop(mat, "array_layer") @@ -268,6 +269,7 @@ def register_properties(): bpy.types.Material.active_render_method_index = bpy.props.IntProperty("Active render method index") bpy.types.Material.receive_shadows = bpy.props.BoolProperty(name="Receive shadows", description="Receive shadows from a shadow map", default=True) 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.instancing = bpy.props.BoolProperty(name="Instanced rendering", description="Use instanced draw calls for objects with this material", 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.uniforms = bpy.props.CollectionProperty(type=MspGLUniform, name="Uniforms", description="Uniform variables to add to the technique") diff --git a/blender/io_mspgl/scene.py b/blender/io_mspgl/scene.py index cb62a1b0..3c98cbee 100644 --- a/blender/io_mspgl/scene.py +++ b/blender/io_mspgl/scene.py @@ -104,6 +104,8 @@ class Scene: instance_list = self.blended_instances if mat.image_based_lighting: self.use_ibl = True + if mat.instancing: + prototype.use_array = True instance = ObjectInstance(obj, prototype) instance_list.append(instance) -- 2.43.0