mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-07 08:21:42 +00:00
Light/radiance (#5252)
* Cam fix, Sun Fix, import-export as json * Ran black formatting
This commit is contained in:
@@ -39,6 +39,10 @@ classes = (
|
||||
operator.ViewFromSun,
|
||||
operator.RefreshIFCMaterials,
|
||||
operator.UnmapMaterial,
|
||||
operator.RADIANCE_OT_select_camera,
|
||||
operator.RADIANCE_OT_export_material_mappings,
|
||||
operator.RADIANCE_OT_import_material_mappings,
|
||||
operator.RADIANCE_OT_open_spectraldb,
|
||||
prop.RadianceMaterial,
|
||||
prop.BIMSolarProperties,
|
||||
prop.RadianceExporterProperties,
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# Bonsai is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Bonsai is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import bpy
|
||||
import json
|
||||
import os
|
||||
@@ -10,6 +29,15 @@ class MATERIAL_UL_radiance_materials(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||
if self.layout_type in {"DEFAULT", "COMPACT"}:
|
||||
row = layout.row(align=True)
|
||||
|
||||
# Adding color preview or glass icon
|
||||
if item.category == "Glass":
|
||||
row.label(icon="SHADING_TEXTURE")
|
||||
else:
|
||||
color_rect = row.row()
|
||||
color_rect.prop(item, "color", text="")
|
||||
color_rect.scale_x = 0.3
|
||||
|
||||
row.prop(item, "name", text="", emboss=False, icon_value=icon)
|
||||
if item.is_mapped:
|
||||
row.label(text=f"{item.category} - {item.subcategory}")
|
||||
|
||||
@@ -30,11 +30,17 @@ import bonsai.tool as tool
|
||||
from pathlib import Path
|
||||
from typing import Union, Optional, Sequence
|
||||
import json
|
||||
import math
|
||||
import time
|
||||
import sun_position
|
||||
import ifcopenshell
|
||||
import webbrowser
|
||||
import ifcopenshell.geom
|
||||
import multiprocessing
|
||||
from mathutils import Vector
|
||||
from bonsai.bim.module.light.data import SolarData
|
||||
from bpy_extras.io_utils import ExportHelper
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
|
||||
ifc_materials = []
|
||||
|
||||
@@ -95,14 +101,10 @@ class ExportOBJ(bpy.types.Operator):
|
||||
while True:
|
||||
shape = iterator.get()
|
||||
materials = shape.geometry.materials
|
||||
# print(shape.geometry)
|
||||
material_ids = shape.geometry.material_ids
|
||||
# material_names = shape.geometry.material_names
|
||||
# print(material_ids)
|
||||
|
||||
for material in materials:
|
||||
# print(material, dir(material))
|
||||
# print(material.name)
|
||||
ifc_materials.append(material.name)
|
||||
|
||||
serialiser.write(shape)
|
||||
@@ -129,10 +131,15 @@ class RadianceRender(bpy.types.Operator):
|
||||
self.report({"ERROR"}, "PyRadiance is not available. Cannot perform rendering.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
# Get the resolution from the user input
|
||||
|
||||
print("Starting Radiance rendering process...")
|
||||
props = context.scene.radiance_exporter_properties
|
||||
resolution_x, resolution_y = props.radiance_resolution_x, props.radiance_resolution_y
|
||||
|
||||
context.scene.render.resolution_x = resolution_x
|
||||
context.scene.render.resolution_y = resolution_y
|
||||
|
||||
aspect_ratio = resolution_x / resolution_y
|
||||
|
||||
quality = props.radiance_quality.upper()
|
||||
detail = props.radiance_detail.upper()
|
||||
variability = props.radiance_variability.upper()
|
||||
@@ -141,6 +148,11 @@ class RadianceRender(bpy.types.Operator):
|
||||
output_file_format = props.output_file_format
|
||||
use_hdr = props.use_hdr
|
||||
choose_hdr_image = props.choose_hdr_image
|
||||
|
||||
print(f"Resolution: {resolution_x}x{resolution_y}")
|
||||
print(f"Quality: {quality}, Detail: {detail}, Variability: {variability}")
|
||||
print(f"Output directory: {output_dir}")
|
||||
|
||||
if use_hdr:
|
||||
hdr_image = "noon_grass_2k.hdr"
|
||||
hdr_mask = "noon_grass_2k_mask.hdr"
|
||||
@@ -148,30 +160,34 @@ class RadianceRender(bpy.types.Operator):
|
||||
hdr_image_path = os.path.join(os.path.dirname(__file__), "HDRs", hdr_image)
|
||||
hdr_mask_path = os.path.join(os.path.dirname(__file__), "HDRs", hdr_mask)
|
||||
sky_map_cal_path = os.path.join(os.path.dirname(__file__), "HDRs", sky_map_cal)
|
||||
# os.chdir(output_dir)
|
||||
|
||||
obj_file_path = os.path.join(output_dir, "model.obj")
|
||||
|
||||
sun_props = context.scene.BIMSolarProperties
|
||||
sun_pos_props = context.scene.sun_pos_properties
|
||||
sky_file_path = os.path.join(output_dir, "sky.rad")
|
||||
latitude = sun_props.latitude
|
||||
longitude = sun_props.longitude
|
||||
timezone = sun_props.timezone
|
||||
month = sun_props.month
|
||||
day = sun_props.day
|
||||
hour = sun_props.hour
|
||||
minute = sun_props.minute
|
||||
# latitude = sun_props.latitude
|
||||
# longitude = sun_props.longitude
|
||||
# month = sun_props.month
|
||||
# day = sun_props.day
|
||||
# hour = sun_props.hour
|
||||
# minute = sun_props.minute
|
||||
|
||||
print("Sun Properties:")
|
||||
print("Latitude: ", latitude)
|
||||
print("Longitude: ", longitude)
|
||||
print("Timezone: ", timezone)
|
||||
print("Month: ", month)
|
||||
print("Day: ", day)
|
||||
print("Hour: ", hour)
|
||||
print("Minute: ", minute)
|
||||
# print("Sun Properties:")
|
||||
# print("Latitude: ", latitude)
|
||||
# print("Longitude: ", longitude)
|
||||
# print("Timezone: ", timezone)
|
||||
# print("Month: ", month)
|
||||
# print("Day: ", day)
|
||||
# print("Hour: ", hour)
|
||||
# print("Minute: ", minute)
|
||||
|
||||
print("Setting up camera...")
|
||||
if props.use_active_camera:
|
||||
camera = context.scene.camera
|
||||
else:
|
||||
camera = props.selected_camera
|
||||
|
||||
camera = self.get_active_camera(context)
|
||||
if camera is None:
|
||||
self.report({"ERROR"}, "No active camera found in the scene. Please add a camera and set it as active.")
|
||||
return {"CANCELLED"}
|
||||
@@ -179,19 +195,34 @@ class RadianceRender(bpy.types.Operator):
|
||||
# Get camera position and direction
|
||||
camera_position, camera_direction = self.get_camera_data(camera)
|
||||
|
||||
dt = datetime(2024, month, day, hour, minute)
|
||||
print(f"Camera position: {camera_position}")
|
||||
print(f"Camera direction: {camera_direction}")
|
||||
|
||||
# azimuth, elevation = sun_position.sun_calc.get_sun_coordinates(
|
||||
# sun_pos_props.time,
|
||||
# sun_pos_props.latitude,
|
||||
# sun_pos_props.longitude,
|
||||
# -sun_pos_props.UTC_zone,
|
||||
# sun_pos_props.month,
|
||||
# sun_pos_props.day,
|
||||
# sun_pos_props.year,
|
||||
# )
|
||||
|
||||
dt = datetime(sun_pos_props.year, sun_props.month, sun_props.day, sun_props.hour, sun_props.minute)
|
||||
|
||||
sky_description = pr.gensky(
|
||||
dt=dt,
|
||||
latitude=latitude,
|
||||
longitude=longitude,
|
||||
timezone=timezone,
|
||||
year=2024,
|
||||
sunny_with_sun=True,
|
||||
sunny_without_sun=False,
|
||||
cloudy=False,
|
||||
ground_reflectance=0.2,
|
||||
turbidity=3.0,
|
||||
# azimuth=64.1,
|
||||
# altitude=-26.6,
|
||||
latitude=sun_props.latitude,
|
||||
longitude=sun_props.longitude,
|
||||
year=sun_pos_props.year,
|
||||
timezone=-int(sun_props.UTC_zone),
|
||||
# sunny_with_sun=False,
|
||||
# sunny_without_sun=False,
|
||||
# cloudy=False,
|
||||
# ground_reflectance=0.2,
|
||||
# turbidity=3.0,
|
||||
)
|
||||
|
||||
sky_description_str = sky_description.decode("utf-8")
|
||||
@@ -292,11 +323,7 @@ ground_glow source ground
|
||||
|
||||
props = context.scene.radiance_exporter_properties
|
||||
|
||||
if props.use_json_file:
|
||||
with open(props.json_file, "r") as file:
|
||||
data = json.load(file)
|
||||
else:
|
||||
data = props.get_mappings_dict()
|
||||
data = props.get_mappings_dict()
|
||||
|
||||
materials_file = os.path.join(output_dir, "materials.rad")
|
||||
written_materials = set()
|
||||
@@ -318,9 +345,6 @@ ground_glow source ground
|
||||
file.write(material)
|
||||
written_materials.add(material.split()[2]) # Add material name to written set
|
||||
|
||||
print(data)
|
||||
print(default_materials)
|
||||
|
||||
for style_id in all_materials:
|
||||
material = next((m for m in props.materials if m.style_id == style_id), None)
|
||||
if material and material.is_mapped:
|
||||
@@ -351,7 +375,7 @@ ground_glow source ground
|
||||
|
||||
self.report({"INFO"}, "Exported Scene file to: {}".format(scene_file))
|
||||
|
||||
# Py Radiance Rendering code
|
||||
print("Setting up Radiance scene...")
|
||||
scene = pr.Scene("ascene")
|
||||
|
||||
material_path = os.path.join(output_dir, "materials.rad")
|
||||
@@ -360,10 +384,39 @@ ground_glow source ground
|
||||
scene.add_material(material_path)
|
||||
scene.add_surface(scene_path)
|
||||
scene.add_source(sky_file_path)
|
||||
print("Setting up view...")
|
||||
if camera.data.type == "PERSP":
|
||||
# Perspective camera
|
||||
camera_fov = camera.data.angle
|
||||
# Calculate vertical FOV based on the desired aspect ratio
|
||||
vertical_fov = 2 * math.atan(math.tan(camera_fov / 2) / aspect_ratio)
|
||||
|
||||
aview = pr.View(position=camera_position, direction=camera_direction)
|
||||
aview = pr.View(
|
||||
vtype="v", # Perspective view
|
||||
position=camera_position,
|
||||
direction=camera_direction,
|
||||
vup=(0, 0, 1), # Assuming Z is up
|
||||
horiz=math.degrees(camera_fov),
|
||||
vert=math.degrees(vertical_fov),
|
||||
)
|
||||
else: # 'ORTHO'
|
||||
# Orthographic camera
|
||||
# Calculate the view size based on the camera's orthographic scale
|
||||
ortho_scale = camera.data.ortho_scale
|
||||
view_width = ortho_scale
|
||||
view_height = ortho_scale / aspect_ratio
|
||||
|
||||
aview = pr.View(
|
||||
vtype="l", # Parallel projection (orthographic)
|
||||
position=camera_position,
|
||||
direction=camera_direction,
|
||||
vup=(0, 0, 1), # Assuming Z is up
|
||||
horiz=view_width,
|
||||
vert=view_height,
|
||||
)
|
||||
scene.add_view(aview)
|
||||
|
||||
print("Starting render...")
|
||||
start_time = time.time()
|
||||
image = pr.render(
|
||||
scene,
|
||||
ambbounce=1,
|
||||
@@ -371,32 +424,34 @@ ground_glow source ground
|
||||
quality=quality,
|
||||
detail=detail,
|
||||
variability=variability,
|
||||
nproc=multiprocessing.cpu_count(),
|
||||
)
|
||||
end_time = time.time()
|
||||
print(f"Render completed in {end_time - start_time:.2f} seconds")
|
||||
|
||||
output_hdr_path = os.path.join(output_dir, f"{output_file_name}.{output_file_format.lower()}")
|
||||
|
||||
print(f"Saving HDR output to: {output_hdr_path}")
|
||||
if output_file_format == "HDR":
|
||||
with open(output_hdr_path, "wb") as wtr:
|
||||
wtr.write(image)
|
||||
else:
|
||||
pass
|
||||
|
||||
print("Applying tone mapping...")
|
||||
pcond_image = pr.pcond(hdr=output_hdr_path, human=True)
|
||||
|
||||
tiff_path = os.path.join(output_dir, f"{output_file_name}.tiff")
|
||||
|
||||
print(f"Saving TIFF output to: {tiff_path}")
|
||||
pr.ra_tiff(inp=pcond_image, out=tiff_path, lzw=True)
|
||||
|
||||
print("Radiance rendering process completed successfully.")
|
||||
self.report({"INFO"}, "Radiance rendering completed. Output: {}".format(tiff_path))
|
||||
return {"FINISHED"}
|
||||
|
||||
def get_active_camera(self, context):
|
||||
if context.scene.camera:
|
||||
props = context.scene.radiance_exporter_properties
|
||||
if props.use_active_camera:
|
||||
return context.scene.camera
|
||||
for obj in context.scene.objects:
|
||||
if obj.type == "CAMERA":
|
||||
return obj
|
||||
return None
|
||||
else:
|
||||
return props.selected_camera
|
||||
|
||||
def get_camera_data(self, camera):
|
||||
# Get camera position
|
||||
@@ -509,9 +564,29 @@ class RefreshIFCMaterials(bpy.types.Operator):
|
||||
for render_item in style.Styles:
|
||||
if render_item.is_a("IfcSurfaceStyleRendering"):
|
||||
style_id = f"IfcSurfaceStyleRendering-{render_item.id()}"
|
||||
ifc_materials.append(style_id)
|
||||
style_name = style.Name or f"Unnamed Style {render_item.id()}"
|
||||
props.add_material_mapping(style_id, style_name)
|
||||
|
||||
# Extract color and transparency
|
||||
color = (1.0, 1.0, 1.0) # Default white
|
||||
transparency = 0.0 # Default opaque
|
||||
if render_item.SurfaceColour:
|
||||
color = (
|
||||
render_item.SurfaceColour.Red,
|
||||
render_item.SurfaceColour.Green,
|
||||
render_item.SurfaceColour.Blue,
|
||||
)
|
||||
if hasattr(render_item, "Transparency") and render_item.Transparency is not None:
|
||||
transparency = render_item.Transparency
|
||||
|
||||
# Add material with color
|
||||
material = props.add_material_mapping(style_id, style_name)
|
||||
material.color = color
|
||||
|
||||
# If transparency is high, consider it as glass
|
||||
if transparency > 0.5:
|
||||
material.category = "Glass"
|
||||
material.subcategory = "Clear Glass"
|
||||
material.is_mapped = True
|
||||
|
||||
props.active_material_index = 0 if props.materials else -1
|
||||
|
||||
@@ -531,3 +606,70 @@ class UnmapMaterial(bpy.types.Operator):
|
||||
material = props.materials[self.material_index]
|
||||
props.unmap_material(material.name)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RADIANCE_OT_select_camera(bpy.types.Operator):
|
||||
bl_idname = "radiance.select_camera"
|
||||
bl_label = "Select Camera"
|
||||
bl_description = "Select a camera from the viewport"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.object is not None and context.object.type == "CAMERA"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.radiance_exporter_properties
|
||||
props.selected_camera = context.object
|
||||
props.use_active_camera = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RADIANCE_OT_export_material_mappings(bpy.types.Operator, ExportHelper):
|
||||
bl_idname = "radiance.export_material_mappings"
|
||||
bl_label = "Export Material Mappings"
|
||||
bl_description = "Export material mappings to a JSON file"
|
||||
|
||||
filename_ext = ".json"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.radiance_exporter_properties
|
||||
mappings = {}
|
||||
|
||||
for material in props.materials:
|
||||
if material.is_mapped:
|
||||
mappings[material.style_id] = {
|
||||
"name": material.name,
|
||||
"category": material.category,
|
||||
"subcategory": material.subcategory,
|
||||
}
|
||||
|
||||
with open(self.filepath, "w") as f:
|
||||
json.dump(mappings, f, indent=4)
|
||||
|
||||
self.report({"INFO"}, f"Material mappings exported to {self.filepath}")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RADIANCE_OT_import_material_mappings(bpy.types.Operator, ImportHelper):
|
||||
bl_idname = "radiance.import_material_mappings"
|
||||
bl_label = "Import Material Mappings"
|
||||
bl_description = "Import material mappings from a JSON file"
|
||||
|
||||
filename_ext = ".json"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.radiance_exporter_properties
|
||||
props.import_mappings(self.filepath)
|
||||
self.report({"INFO"}, f"Material mappings imported from {self.filepath}")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RADIANCE_OT_open_spectraldb(bpy.types.Operator):
|
||||
bl_idname = "radiance.open_spectraldb"
|
||||
bl_label = "Open SpectralDB"
|
||||
bl_description = "Open the SpectralDB website for reference"
|
||||
|
||||
def execute(self, context):
|
||||
webbrowser.open("https://spectraldb.com")
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -32,6 +32,7 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
BoolProperty,
|
||||
CollectionProperty,
|
||||
PointerProperty,
|
||||
)
|
||||
import os
|
||||
from bpy.types import PropertyGroup
|
||||
@@ -107,6 +108,11 @@ def update_display_sun_path(self, context):
|
||||
SolarDecorator.uninstall()
|
||||
|
||||
|
||||
def update_resolution(self, context):
|
||||
context.scene.render.resolution_x = self.radiance_resolution_x
|
||||
context.scene.render.resolution_y = self.radiance_resolution_y
|
||||
|
||||
|
||||
def update_sun_path():
|
||||
if not SolarData.is_loaded:
|
||||
SolarData.load()
|
||||
@@ -142,6 +148,10 @@ def update_sun_path():
|
||||
rotation_euler = Euler((elevation - pi / 2, 0, -azimuth))
|
||||
rotation_quaternion = rotation_euler.to_quaternion()
|
||||
|
||||
props.azimuth = azimuth
|
||||
props.elevation = elevation
|
||||
props.UTC_zone = zone
|
||||
|
||||
if sun_vector.z < 0:
|
||||
bpy.context.scene.display.light_direction = mat @ Vector((0, 0, 1))
|
||||
else:
|
||||
@@ -162,14 +172,11 @@ class RadianceMaterial(PropertyGroup):
|
||||
category: StringProperty(name="Category")
|
||||
subcategory: StringProperty(name="Subcategory")
|
||||
is_mapped: BoolProperty(name="Is Mapped", default=False)
|
||||
color: FloatVectorProperty(name="Color", subtype="COLOR", default=(1.0, 1.0, 1.0), min=0.0, max=1.0, size=3)
|
||||
|
||||
|
||||
class RadianceExporterProperties(PropertyGroup):
|
||||
|
||||
def update_json_file(self, context):
|
||||
if self.json_file:
|
||||
self.json_file = bpy.path.abspath(self.json_file)
|
||||
|
||||
def update_output_dir(self, context):
|
||||
if self.output_dir:
|
||||
self.output_dir = bpy.path.abspath(self.output_dir)
|
||||
@@ -184,8 +191,26 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
item.style_id = style_id
|
||||
item.category = ""
|
||||
item.subcategory = ""
|
||||
item.color = (1.0, 1.0, 1.0) # Default white
|
||||
return item
|
||||
|
||||
def import_mappings(self, filepath):
|
||||
with open(filepath, "r") as f:
|
||||
mappings = json.load(f)
|
||||
|
||||
for style_id, mapping in mappings.items():
|
||||
material = self.get_material_mapping(mapping["name"])
|
||||
if material:
|
||||
material.style_id = style_id
|
||||
material.category = mapping["category"]
|
||||
material.subcategory = mapping["subcategory"]
|
||||
material.is_mapped = True
|
||||
else:
|
||||
new_material = self.add_material_mapping(style_id, mapping["name"])
|
||||
new_material.category = mapping["category"]
|
||||
new_material.subcategory = mapping["subcategory"]
|
||||
new_material.is_mapped = True
|
||||
|
||||
def get_material_mapping(self, style_name):
|
||||
return next((item for item in self.materials if item.name == style_name), None)
|
||||
|
||||
@@ -213,12 +238,6 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
item.subcategory = ""
|
||||
item.is_mapped = False
|
||||
|
||||
use_json_file: BoolProperty(
|
||||
name="Upload JSON",
|
||||
description="Toggle between uploading a JSON file and using in-UI material mapping",
|
||||
default=False,
|
||||
)
|
||||
|
||||
is_exporting: bpy.props.BoolProperty(
|
||||
name="Is Exporting", description="Whether the OBJ export is in progress", default=False
|
||||
)
|
||||
@@ -237,6 +256,7 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
("Plant", "Plant", ""),
|
||||
("Exterior", "Exterior", ""),
|
||||
("Color Swatch", "Color Swatch", ""),
|
||||
("Glass", "Glass", ""),
|
||||
]
|
||||
|
||||
def update_material_mapping(self, context):
|
||||
@@ -269,14 +289,13 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
should_load_from_memory: BoolProperty(
|
||||
name="Load from Memory",
|
||||
default=False,
|
||||
description="Use IFC file currently loaded in Bonsai",
|
||||
)
|
||||
|
||||
radiance_resolution_x: IntProperty(
|
||||
name="X", description="Horizontal resolution of the output image", default=1920, min=1
|
||||
name="X", description="Horizontal resolution of the output image", default=1920, min=1, update=update_resolution
|
||||
)
|
||||
radiance_resolution_y: IntProperty(
|
||||
name="Y", description="Vertical resolution of the output image", default=1080, min=1
|
||||
name="Y", description="Vertical resolution of the output image", default=1080, min=1, update=update_resolution
|
||||
)
|
||||
output_dir: StringProperty(
|
||||
name="Output Directory",
|
||||
@@ -292,13 +311,6 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
subtype="FILE_PATH",
|
||||
update=lambda self, context: self.update_ifc_file(context),
|
||||
)
|
||||
json_file: StringProperty(
|
||||
name="JSON File",
|
||||
description="Path to the JSON file",
|
||||
default="",
|
||||
subtype="FILE_PATH",
|
||||
update=lambda self, context: self.update_json_file(context),
|
||||
)
|
||||
|
||||
radiance_quality: EnumProperty(
|
||||
name="Quality",
|
||||
@@ -350,6 +362,17 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
default="Noon",
|
||||
)
|
||||
|
||||
use_active_camera: BoolProperty(
|
||||
name="Use Active Camera", description="Use the active camera in the scene", default=True
|
||||
)
|
||||
|
||||
selected_camera: PointerProperty(
|
||||
type=bpy.types.Object,
|
||||
name="Camera",
|
||||
description="Select a camera to use for rendering",
|
||||
poll=lambda self, object: object.type == "CAMERA",
|
||||
)
|
||||
|
||||
|
||||
class BIMSolarProperties(PropertyGroup):
|
||||
sites: EnumProperty(items=get_sites, name="Sites")
|
||||
@@ -364,6 +387,9 @@ class BIMSolarProperties(PropertyGroup):
|
||||
sun_position: FloatVectorProperty(name="Sun Position", subtype="XYZ", default=(0, 0, 0))
|
||||
sun_path_origin: FloatVectorProperty(name="Sun Path Origin", subtype="XYZ", default=(0, 0, 0))
|
||||
sun_path_size: FloatProperty(name="Sun Path Size", min=0.1, default=50, update=update_sun_path_size)
|
||||
azimuth: FloatProperty(name="Azimuth")
|
||||
elevation: FloatProperty(name="Elevation")
|
||||
UTC_zone: FloatProperty(name="UTC Zone")
|
||||
display_shadows: BoolProperty(
|
||||
name="Display Shadows",
|
||||
default=False,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"Glass": {
|
||||
"Clear Glass": "void BRTDfunc clear_glass\n10\n sr_clear_r sr_clear_g sr_clear_b\n st_clear_r st_clear_g st_clear_b\n 0 0 0\n glaze1.cal\n0\n19\n 0 0 0\n 0 0 0\n 0 0 0\n 1\n 0.074 0.077 0.079\n 0.074 0.077 0.079\n 0.862 0.890 0.886\n"
|
||||
},
|
||||
"Wall": {
|
||||
"White Painted Room Walls": "void plastic white_painted_room_walls \n0\n0\n5 0.8316 0.8116 0.7226 0.0036 0.2",
|
||||
"White Painted Corridor Walls": "void plastic white_painted_corridor_walls \n0\n0\n5 0.8143 0.7984 0.715 0.0039 0.2",
|
||||
|
||||
@@ -50,43 +50,52 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
|
||||
row.prop(props, "output_dir")
|
||||
|
||||
row = layout.row()
|
||||
layout.prop(props, "use_json_file")
|
||||
layout.label(text="Info: Unmapped materials default to white")
|
||||
row = layout.row()
|
||||
row.template_list("MATERIAL_UL_radiance_materials", "", props, "materials", props, "active_material_index")
|
||||
row.operator("radiance.open_spectraldb", text="", icon="WORLD") # Globe icon
|
||||
if len(props.materials) > 0:
|
||||
col = layout.column(align=True)
|
||||
col.prop(props, "category")
|
||||
if props.category:
|
||||
col.prop(props, "subcategory")
|
||||
|
||||
if props.use_json_file:
|
||||
row = layout.row()
|
||||
row.prop(props, "json_file")
|
||||
if props.active_material_index >= 0 and props.active_material_index < len(props.materials):
|
||||
active_material = props.materials[props.active_material_index]
|
||||
if active_material.category and active_material.subcategory:
|
||||
layout.label(
|
||||
text=f"Mapped: {active_material.name} to {active_material.category} - {active_material.subcategory}"
|
||||
)
|
||||
else:
|
||||
layout.label(text=f"Select category and subcategory for: {active_material.name}")
|
||||
|
||||
if not props.use_json_file:
|
||||
row = layout.row()
|
||||
layout.label(text="Info: Unmapped materials default to white")
|
||||
row = layout.row()
|
||||
row.template_list("MATERIAL_UL_radiance_materials", "", props, "materials", props, "active_material_index")
|
||||
|
||||
if len(props.materials) > 0:
|
||||
col = layout.column(align=True)
|
||||
col.prop(props, "category")
|
||||
if props.category:
|
||||
col.prop(props, "subcategory")
|
||||
|
||||
if props.active_material_index >= 0 and props.active_material_index < len(props.materials):
|
||||
active_material = props.materials[props.active_material_index]
|
||||
if active_material.category and active_material.subcategory:
|
||||
layout.label(
|
||||
text=f"Mapped: {active_material.name} to {active_material.category} - {active_material.subcategory}"
|
||||
)
|
||||
else:
|
||||
layout.label(text=f"Select category and subcategory for: {active_material.name}")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.refresh_ifc_materials", text="Refresh IFC Materials")
|
||||
row = layout.row()
|
||||
row.operator("radiance.import_material_mappings", text="Import Mappings", icon="IMPORT")
|
||||
row.operator("radiance.export_material_mappings", text="Export Mappings", icon="EXPORT")
|
||||
row = layout.row()
|
||||
row.operator("bim.refresh_ifc_materials", text="Refresh IFC Materials")
|
||||
|
||||
layout.separator()
|
||||
row = layout.row()
|
||||
row.label(text="Resolution")
|
||||
row.prop(props, "radiance_resolution_x", text="X")
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="")
|
||||
layout.label(text="Step 1: Export geometry for simulation")
|
||||
row = layout.row()
|
||||
row.operator("export_scene.radiance", text="Export Geometry for Simulation")
|
||||
|
||||
layout.separator()
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Camera Settings")
|
||||
row = box.row()
|
||||
row.prop(props, "use_active_camera")
|
||||
if not props.use_active_camera:
|
||||
row = box.row()
|
||||
row.prop(props, "selected_camera")
|
||||
row.operator("radiance.select_camera", text="", icon="EYEDROPPER")
|
||||
|
||||
row = box.row(align=True)
|
||||
row.label(text="Resolution")
|
||||
row.prop(props, "radiance_resolution_x", text="X")
|
||||
row.prop(props, "radiance_resolution_y", text="Y")
|
||||
|
||||
row = layout.row()
|
||||
@@ -115,8 +124,7 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
|
||||
row.prop(props, "choose_hdr_image")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("export_scene.radiance", text="Export Geometry for Simulation")
|
||||
|
||||
layout.label(text="Step 2: Run the simulation")
|
||||
row = layout.row()
|
||||
row.operator("render_scene.radiance", text="Radiance Render")
|
||||
row.enabled = not props.is_exporting
|
||||
|
||||
Reference in New Issue
Block a user