import math from types import SimpleNamespace import unreal from .camera import look_at # Calibrated in tools/smoke_basics.py against the fixed exposure from camera.create. _CUBEMAP_AMBIENT = 30.0 _FOG_LUMINANCE = 30.0 def _setup(actor, component_class, intensity, color): light = actor.get_component_by_class(component_class) light.set_mobility(unreal.ComponentMobility.MOVABLE) light.set_editor_property("intensity", float(intensity)) light.set_light_color(unreal.LinearColor(*color, 1.0)) return light def area(scene, name="Light", location=(200, -200, 350), target=(0, 0, 100), intensity=12000, color=(1, 1, 1), size=180): actor = scene.spawn(unreal.RectLight, name, location) light = _setup(actor, unreal.RectLightComponent, intensity, color) light.set_editor_property("source_width", float(size)) light.set_editor_property("source_height", float(size)) light.set_editor_property("attenuation_radius", 2000.0) look_at(actor, target) return actor def point(scene, name="Point", location=(0, 0, 250), intensity=10000, color=(1, 1, 1)): """Bulb shining in all directions.""" actor = scene.spawn(unreal.PointLight, name, location) light = _setup(actor, unreal.PointLightComponent, intensity, color) light.set_editor_property("attenuation_radius", 2000.0) return actor def spot(scene, name="Spot", location=(200, -200, 400), target=(0, 0, 100), intensity=20000, color=(1, 1, 1), angle=30): """Cone of light; angle is measured in degrees from the cone axis.""" actor = scene.spawn(unreal.SpotLight, name, location) light = _setup(actor, unreal.SpotLightComponent, intensity, color) light.set_editor_property("attenuation_radius", 2000.0) light.set_editor_property("outer_cone_angle", float(angle)) light.set_editor_property("inner_cone_angle", float(angle) * 0.7) look_at(actor, target) return actor def sun(scene, name="Sun", location=(300, -300, 500), target=(0, 0, 0), intensity=500, color=(1, 1, 1)): """Parallel light for the whole scene; only the location-target direction matters.""" actor = scene.spawn(unreal.DirectionalLight, name, location) light = _setup(actor, unreal.DirectionalLightComponent, intensity, color) light.set_atmosphere_sun_light(True) look_at(actor, target) return actor def environment(scene, sky=True, sun_intensity=500, sun_angle=45, sun_yaw=-45, ambient=1.0, fog=0.0, fog_color=(0.6, 0.7, 0.9)): """Add a world around the scene: sky, sun, ambient light and height fog. sun_angle is the height above the horizon in degrees (low = sunset), sun_yaw its compass direction. sky=False keeps a black background with ambient light. The sky is lit only by the sun: for night use sky=False, sun_intensity=0, ambient=0.3. Returns .sun (None when sun_intensity=0), usable with shot.light_key. """ for name, value in (("sun_intensity", sun_intensity), ("ambient", ambient), ("fog", fog)): if value < 0: raise ValueError(f"{name} nie moze byc ujemne.") sun_actor = None if sun_intensity > 0: height, compass = math.radians(sun_angle), math.radians(sun_yaw) direction = (math.cos(height) * math.cos(compass), math.cos(height) * math.sin(compass), math.sin(height)) sun_actor = sun(scene, location=tuple(1000 * value for value in direction), intensity=sun_intensity) sun_actor.get_component_by_class(unreal.DirectionalLightComponent).set_atmosphere_sun_light(sky) # Also for sky=False: an unlit atmosphere keeps the background black, not white. scene.spawn(unreal.SkyAtmosphere, "Sky") ambient_actor = scene.spawn(unreal.SkyLight, "Ambient") light = ambient_actor.light_component light.set_mobility(unreal.ComponentMobility.MOVABLE) if sky: light.set_editor_property("real_time_capture", True) light.set_intensity(float(ambient)) else: light.set_editor_property("source_type", unreal.SkyLightSourceType.SLS_SPECIFIED_CUBEMAP) light.set_cubemap(unreal.load_asset("/Engine/MapTemplates/Sky/DaylightAmbientCubemap")) light.set_intensity(float(ambient) * _CUBEMAP_AMBIENT) if fog > 0: component = scene.spawn(unreal.ExponentialHeightFog, "Fog").component component.set_fog_density(float(fog)) component.set_editor_property("fog_inscattering_luminance", unreal.LinearColor( *(value * _FOG_LUMINANCE for value in fog_color), 1.0)) return SimpleNamespace(sun=sun_actor) def studio(scene, key_color=(1.0, 0.82, 0.65), fill_color=(0.5, 0.7, 1.0)): return [area(scene, "Key", (200, -500, 350), color=key_color), area(scene, "Fill", (100, 300, 250), intensity=7000, color=fill_color), area(scene, "Rim", (-200, 0, 300), intensity=15000)]