Source code for simvx.graphics.renderer.environment_sync

"""WorldEnvironment synchronisation and custom post-process orchestration."""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any

import vulkan as vk

if TYPE_CHECKING:
    from .forward import ForwardRenderer
    from .post_process import PostProcessPass

__all__ = ["EnvironmentSync"]

log = logging.getLogger(__name__)


[docs] class EnvironmentSync: """Syncs WorldEnvironment node properties to renderer settings and manages custom post-processing.""" def __init__(self, renderer: ForwardRenderer) -> None: self._r = renderer
[docs] def sync_world_environment(self) -> None: """Sync WorldEnvironment node properties to renderer settings.""" r = self._r from simvx.core.world_environment import WorldEnvironment tree = getattr(r._engine, "_scene_tree", None) or getattr(r._engine, "scene_tree", None) if not tree or not tree.root: return env = tree.root.find(WorldEnvironment) if not env: return pp = r._post_process if pp: pp.bloom_enabled = env.bloom_enabled pp.bloom_threshold = env.bloom_threshold pp.bloom_intensity = env.bloom_intensity pp.ssao_enabled = env.ssao_enabled pp.exposure = env.tonemap_exposure pp.dof_enabled = env.dof_enabled pp.dof_focus_distance = env.dof_focus_distance pp.dof_focus_range = env.dof_focus_range pp.motion_blur_enabled = env.motion_blur_enabled pp.motion_blur_intensity = env.motion_blur_intensity pp.motion_blur_samples = env.motion_blur_samples pp.grain_enabled = env.film_grain_enabled pp.grain_intensity = env.film_grain_intensity pp.vignette_enabled = env.vignette_enabled pp.vignette_intensity = env.vignette_intensity pp.vignette_smoothness = env.vignette_smoothness pp.chromatic_aberration_enabled = env.chromatic_aberration_enabled pp.chromatic_aberration_intensity = env.chromatic_aberration_intensity if r._ssao_pass: r._ssao_pass.enabled = env.ssao_enabled # Fog is applied post-tonemap in the fullscreen pass (not as a compute pass) mode_map = {"linear": 0.0, "exponential": 1.0, "exponential_squared": 2.0} if pp: pp.fog_enabled = env.fog_enabled pp.fog_colour = env.fog_colour[:3] pp.fog_density = env.fog_density pp.fog_start = env.fog_start pp.fog_end = env.fog_end pp.fog_mode = mode_map.get(env.fog_mode, 1.0) # Sync sky colour to engine clear colour if env.sky_mode == "colour": c = env.sky_colour_top if len(c) >= 4: r._engine.clear_colour = [c[0], c[1], c[2], c[3]] elif len(c) >= 3: r._engine.clear_colour = [c[0], c[1], c[2], 1.0] cg = getattr(pp, "colour_grading", None) if pp else None if cg and env.colour_grading_enabled: cg.enabled = True
[docs] def run_custom_post_process(self, cmd: Any, pp: PostProcessPass) -> None: """Execute custom user effects between built-in post-processing and tonemap.""" r = self._r if not r._custom_pp or not pp.hdr_target: return # Collect effects from WorldEnvironment nodes in the scene tree effects = self._gather_post_process_effects() if not effects: return r._custom_pp.sync_effects(effects) if not r._custom_pp.has_effects: return w, h = r._engine.extent hdr_view = pp.hdr_target.color_view depth_view = pp.hdr_target.depth_view result_view = r._custom_pp.render(cmd, hdr_view, depth_view, w, h) # If custom effects produced output, update tonemap's HDR input descriptor if result_view and result_view != hdr_view: self._update_tonemap_hdr_input(result_view)
def _gather_post_process_effects(self) -> list: """Collect PostProcessEffects from all WorldEnvironment nodes in the scene.""" from simvx.core.world_environment import WorldEnvironment r = self._r tree = getattr(r._engine, "_scene_tree", None) or getattr(r._engine, "scene_tree", None) if not tree: return [] root = getattr(tree, "root", None) if not root: return [] effects = [] for node in root.find_all(WorldEnvironment): effects.extend(node.get_post_processes()) effects.sort(key=lambda e: e.order) return effects
[docs] def update_tonemap_hdr_input(self, new_hdr_view: Any) -> None: """Rewrite the tonemap descriptor set binding 0 to point at the custom output.""" self._update_tonemap_hdr_input(new_hdr_view)
def _update_tonemap_hdr_input(self, new_hdr_view: Any) -> None: """Rewrite the tonemap descriptor set binding 0 to point at the custom output.""" r = self._r pp = r._post_process if not pp or not pp._descriptor_set or not pp._sampler: return hdr_info = vk.VkDescriptorImageInfo( sampler=pp._sampler, imageView=new_hdr_view, imageLayout=vk.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, ) vk.vkUpdateDescriptorSets(r._engine.ctx.device, 1, [vk.VkWriteDescriptorSet( dstSet=pp._descriptor_set, dstBinding=0, dstArrayElement=0, descriptorCount=1, descriptorType=vk.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, pImageInfo=[hdr_info], )], 0, None)