diff --git a/src/blenderbim/blenderbim/bim/module/light/__init__.py b/src/blenderbim/blenderbim/bim/module/light/__init__.py index 5aa65bec18..f1a3162234 100644 --- a/src/blenderbim/blenderbim/bim/module/light/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/light/__init__.py @@ -21,17 +21,14 @@ from . import ui, prop, operator classes = ( - operator.ExportRadiance, + operator.ExportOBJ, + operator.RadianceRender, prop.RadianceExporterProperties, ui.BIM_PT_radiance_exporter, ) def register(): - # for cls in classes: - # bpy.utils.register_class(cls) bpy.types.Scene.radiance_exporter_properties = bpy.props.PointerProperty(type=prop.RadianceExporterProperties) def unregister(): - # for cls in reversed(classes): - # bpy.utils.unregister_class(cls) del bpy.types.Scene.radiance_exporter_properties \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/module/light/operator.py b/src/blenderbim/blenderbim/bim/module/light/operator.py index 2934b2a422..898d4462f0 100644 --- a/src/blenderbim/blenderbim/bim/module/light/operator.py +++ b/src/blenderbim/blenderbim/bim/module/light/operator.py @@ -26,16 +26,193 @@ import json import ifcopenshell import ifcopenshell.geom import multiprocessing +import shutil -class ExportRadiance(bpy.types.Operator): - """Exports and renders the scene with Radiance using rad""" + + +class ExportOBJ(bpy.types.Operator): + """Exports the IFC File to OBJ""" bl_idname = "export_scene.radiance" - bl_label = "Export and Render" - bl_description = "Export the scene to Radiance and render it" + bl_label = "Export" + bl_description = "Export the IFC to OBJ" def execute(self, context): - return {'FINISHED'} + # Get the resolution from the user input + resolution_x, resolution_y = self.getResolution(context) + quality = context.scene.radiance_exporter_properties.radiance_quality.upper() + detail = context.scene.radiance_exporter_properties.radiance_detail.upper() + variability = context.scene.radiance_exporter_properties.radiance_variability.upper() + + # Calculate the aspect ratio + aspect_ratio = resolution_x / resolution_y + # Get the blend file path and create the "Radiance Rendering" directory + self.report({'INFO'}, "Exporting Radiance files...") + blend_file_path = bpy.data.filepath + if not blend_file_path: + self.report({'ERROR'}, "Please save the Blender file before exporting.") + return {'CANCELLED'} + + blend_file_dir = os.path.dirname(blend_file_path) + radiance_dir = os.path.join(blend_file_dir, "RadianceRendering") + + self.report({'INFO'}, "Radiance directory: {}".format(radiance_dir)) + + if not os.path.exists(radiance_dir): + os.makedirs(radiance_dir) + + # IFC file export and processing + settings = ifcopenshell.geom.settings() + # Settings for obj + + serializer_settings = ifcopenshell.geom.serializer_settings() + + + settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SURFACES_AND_SOLIDS) + settings.set("apply-default-materials", True) + serializer_settings.set("use-element-guids", True) + settings.set("use-world-coords", True) + + ifc_file_name = context.scene.radiance_exporter_properties.ifc_file_name + ifc_file_path = os.path.join(blend_file_dir, f"{ifc_file_name}.ifc") + + if not os.path.exists(ifc_file_path): + self.report({'ERROR'}, f"IFC file not found: {ifc_file_path}") + return {'CANCELLED'} + + + ifc_file = ifcopenshell.open(ifc_file_path) + for material in ifc_file.by_type("IfcMaterial"): + self.report({'INFO'}, f"Material: {material.Name}, ID: {material.id()}") + + obj_file_path = os.path.join(radiance_dir, "model.obj") + mtl_file_path = os.path.join(radiance_dir, "model.mtl") + + + # serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, ifcopenshell.geom.serializer_settings()) + serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, serializer_settings) + serialiser.setFile(ifc_file) + serialiser.setUnitNameAndMagnitude("METER", 1.0) + serialiser.writeHeader() + + iterator = ifcopenshell.geom.iterator(settings, ifc_file, multiprocessing.cpu_count()) + if iterator.initialize(): + while True: + serialiser.write(iterator.get()) + if not iterator.next(): + break + serialiser.finalize() + + return {'FINISHED'} + + def getResolution(self, context): + scene = context.scene + props = scene.radiance_exporter_properties + resolution_x = props.radiance_resolution_x + resolution_y = props.radiance_resolution_y + return resolution_x, resolution_y + + +class RadianceRender(bpy.types.Operator): + """Radiance Rendering""" + bl_idname = "render_scene.radiance" + bl_label = "Render" + bl_description = "Renders the scene using Radiance" + + def execute(self, context): + # Get the resolution from the user input + resolution_x, resolution_y = self.getResolution(context) + quality = context.scene.radiance_exporter_properties.radiance_quality.upper() + detail = context.scene.radiance_exporter_properties.radiance_detail.upper() + variability = context.scene.radiance_exporter_properties.radiance_variability.upper() + + # Get the blend file path and create the "Radiance Rendering" directory + blend_file_path = bpy.data.filepath + if not blend_file_path: + self.report({'ERROR'}, "Please save the Blender file before rendering.") + return {'CANCELLED'} + + blend_file_dir = os.path.dirname(blend_file_path) + radiance_dir = os.path.join(blend_file_dir, "RadianceRendering") + + + # Material processing + style = [] + obj_file_path = os.path.join(radiance_dir, "model.obj") + with open(obj_file_path, "r") as obj_file: + # Iterate through each line in the file + for line in obj_file: + # Check if the line starts with "usemtl" + if line.startswith("usemtl"): + l = line.strip().split(" ") + style.append(l[1]) + + # json_file_path = os.path.join(blend_file_dir, "material_mapping.json") + + json_file_path = context.scene.radiance_exporter_properties.json_file_path + self.report({'INFO'}, f"Selected JSON file: {json_file_path}") + if json_file_path: + # self.report({'INFO'}, f"Selected JSON file: {json_file_name}") + json_dest_path = os.path.join(blend_file_dir, json_file_path.split("\\")[-1]) + shutil.copy(json_file_path, json_dest_path) + self.report({'INFO'}, f"JSON file saved to: {json_dest_path}") + else: + self.report({'WARNING'}, "No JSON file selected") + + + with open(json_file_path, 'r') as file: + data = json.load(file) + + # Create materials.rad file + materials_file = os.path.join(radiance_dir, "materials.rad") + with open(materials_file, "w") as file: + file.write("void plastic white\n0\n0\n5 1 1 1 0 0\n") + file.write("void plastic blue_plastic\n0\n0\n5 0.1 0.2 0.8 0.05 0.1\n") + file.write("void plastic red_plastic\n0\n0\n5 0.8 0.1 0.2 0.05 0.1\n") + file.write("void metal silver_metal\n0\n0\n5 0.8 0.8 0.8 0.9 0.1\n") + file.write("void glass clear_glass\n0\n0\n3 0.96 0.96 0.96\n") + file.write("void light white_light\n0\n0\n3 1.0 1.0 1.0\n") + file.write("void trans olive_trans\n0\n0\n7 0.6 0.7 0.4 0.05 0.05 0.7 0.2\n") + + for i in set(style): + file.write("inherit alias " + i + " " + data.get(i, "white") + "\n") + + self.report({'INFO'}, "Exported Materials Rad file to: {}".format(materials_file)) + + # Run obj2mesh + rtm_file_path = os.path.join(radiance_dir, "model.rtm") + mesh_file_path = save_obj2mesh_output(obj_file_path, rtm_file_path, matfiles=[materials_file]) + # subprocess.run(["obj2mesh", "-a", materials_file, obj_file_path, rtm_file_path]) + self.report({'INFO'}, "obj2mesh output: {}".format(mesh_file_path)) + scene_file = os.path.join(radiance_dir, "scene.rad") + with open(scene_file, "w") as file: + file.write("void mesh model\n1 " + rtm_file_path + "\n0\n0\n") + + self.report({'INFO'}, "Exported Scene file to: {}".format(scene_file)) + + # Py Radiance Rendering code + scene = pr.Scene("ascene") + + material_path = os.path.join(radiance_dir, "materials.rad") + scene_path = os.path.join(radiance_dir, "scene.rad") + + scene.add_material(material_path) + scene.add_surface(scene_path) + + aview = pr.View(position=(1, 1.5, 1), direction=(1, 0, 0)) + scene.add_view(aview) + + octpath = os.path.join(blend_file_dir, "ascene.oct") + print("Reached here") + image = pr.render(scene, ambbounce=1, resolution=(resolution_x, resolution_y), + quality=quality, detail=detail, variability=variability) + + raw_hdr_path = os.path.join(radiance_dir, "raw.hdr") + with open(raw_hdr_path, "wb") as wtr: + wtr.write(image) + + self.report({'INFO'}, "Radiance rendering completed. Output: {}".format(raw_hdr_path)) + return {'FINISHED'} def getResolution(self, context): scene = context.scene @@ -46,5 +223,7 @@ class ExportRadiance(bpy.types.Operator): def save_obj2mesh_output(inp: Union[bytes, str, Path], output_file: str, **kwargs): output_bytes = pr.obj2mesh(inp, **kwargs) + with open(output_file, 'wb') as f: - f.write(output_bytes) \ No newline at end of file + f.write(output_bytes) + return output_file \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/module/light/prop.py b/src/blenderbim/blenderbim/bim/module/light/prop.py index 12f7d39d4d..9850a1b0db 100644 --- a/src/blenderbim/blenderbim/bim/module/light/prop.py +++ b/src/blenderbim/blenderbim/bim/module/light/prop.py @@ -21,6 +21,14 @@ from bpy.props import IntProperty, StringProperty, EnumProperty from bpy.types import PropertyGroup class RadianceExporterProperties(PropertyGroup): + + def update_json_file_path(self, context): + if self.json_file_path: + self.json_file_path = bpy.path.abspath(self.json_file_path) + + + + radiance_resolution_x: IntProperty( name="X", description="Horizontal resolution of the output image", @@ -36,8 +44,17 @@ class RadianceExporterProperties(PropertyGroup): ifc_file_name: StringProperty( name="IFC File Name", description="Name of the IFC file to use (without .ifc extension)", - default="AC20-FZK-Haus" + default="" ) + + json_file_path: StringProperty( + name="JSON File", + description="Path to the JSON file", + default="", + subtype="FILE_PATH", + update=lambda self, context: self.update_json_file_path(context) + ) + radiance_quality: EnumProperty( name="Quality", description="Radiance rendering quality", diff --git a/src/blenderbim/blenderbim/bim/module/light/ui.py b/src/blenderbim/blenderbim/bim/module/light/ui.py index 3abb7d0f79..ab7e0c42cf 100644 --- a/src/blenderbim/blenderbim/bim/module/light/ui.py +++ b/src/blenderbim/blenderbim/bim/module/light/ui.py @@ -36,6 +36,9 @@ class BIM_PT_radiance_exporter(bpy.types.Panel): row = layout.row() row.prop(props, "ifc_file_name") + + row = layout.row() + row.prop(props, "json_file_path") row = layout.row() row.label(text="Resolution") @@ -55,4 +58,7 @@ class BIM_PT_radiance_exporter(bpy.types.Panel): row.prop(props, "radiance_variability") row = layout.row() - row.operator("export_scene.radiance", text="Export and Render") \ No newline at end of file + row.operator("export_scene.radiance", text="Export to OBJ") + + row = layout.row() + row.operator("render_scene.radiance", text="Radiance Render") \ No newline at end of file