voxcity.visualizer.renderer_gpu =============================== .. py:module:: voxcity.visualizer.renderer_gpu .. autoapi-nested-parse:: GPU-accelerated renderer using Taichi for ray tracing. This module provides GPU-accelerated rendering functionality for VoxCity visualization, using Taichi for parallel ray tracing on GPU. Based on ray-tracing-one-weekend-taichi implementation, extended for triangle mesh support. Attributes ---------- .. autoapisummary:: voxcity.visualizer.renderer_gpu.Vector3 voxcity.visualizer.renderer_gpu.REFLECTIVE_CLASSES voxcity.visualizer.renderer_gpu.METALLIC_CLASSES Classes ------- .. toctree:: :hidden: /autoapi/voxcity/visualizer/renderer_gpu/GPURenderer .. autoapisummary:: voxcity.visualizer.renderer_gpu.GPURenderer Functions --------- .. autoapisummary:: voxcity.visualizer.renderer_gpu.light_direction_from_angles voxcity.visualizer.renderer_gpu.build_bvh_fast voxcity.visualizer.renderer_gpu.merge_meshes voxcity.visualizer.renderer_gpu.visualize_voxcity_gpu Module Contents --------------- .. py:function:: light_direction_from_angles(azimuth_deg: float, elevation_deg: float) -> Tuple[float, float, float] Convert azimuth and elevation angles to light direction vector (Z-up). :param azimuth_deg: Angle in XY plane from X-axis (0°=East, 90°=North), in degrees :param elevation_deg: Angle above horizon (0°=horizontal, 90°=zenith), in degrees :returns: Normalized (x, y, z) direction vector pointing toward the light source .. py:function:: build_bvh_fast(vertices: numpy.ndarray, indices: numpy.ndarray) -> Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray] Build BVH using fast iterative construction with vectorized operations. Returns arrays for GPU consumption: - bvh_triangle_id: triangle ID at each node (-1 for internal) - bvh_left_id: left child ID (-1 for none) - bvh_right_id: right child ID (-1 for none) - bvh_next_id: next node in traversal (-1 for none) - bvh_min: bounding box min (N, 3) - bvh_max: bounding box max (N, 3) .. py:data:: Vector3 .. py:data:: REFLECTIVE_CLASSES .. py:data:: METALLIC_CLASSES .. py:function:: merge_meshes(mesh_collection: voxcity.models.MeshCollection, exclude_classes: Optional[set] = None) -> Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray] Merge all meshes in a collection into single arrays with material assignments. :param mesh_collection: Collection of meshes to merge :type mesh_collection: MeshCollection :param exclude_classes: Set of class IDs to exclude from merging (e.g., {-3} to skip buildings) :type exclude_classes: set, optional :returns: * **vertices** (*np.ndarray*) -- (N, 3) combined vertices * **indices** (*np.ndarray*) -- (M, 3) combined triangle indices * **colors** (*np.ndarray*) -- (M, 3) combined face colors * **materials** (*np.ndarray*) -- (M,) material types per face (0=Lambert, 1=Metal, 2=Dielectric) .. py:function:: visualize_voxcity_gpu(city: voxcity.models.VoxCity, voxel_color_map: str | dict = 'default', width: int = 1920, height: int = 1080, samples_per_pixel: int = 64, max_depth: int = 8, camera_position: Optional[Tuple[float, float, float]] = None, camera_look_at: Optional[Tuple[float, float, float]] = None, fov: float = 25.0, output_path: Optional[str] = None, show_progress: bool = True, arch: str = 'gpu', rotation: bool = False, output_directory: str = 'output', rotation_frames: int = 240, rotation_file_prefix: str = 'city_rotation', multi_view: bool = False, multi_view_file_prefix: str = 'city_view', views: Optional[List[str]] = None, floor_enabled: bool = True, light_direction: Optional[Tuple[float, float, float]] = None, direct: Optional[Tuple[float, float, float]] = None, ambient: Optional[Tuple[float, float, float]] = None, background_color: Optional[Tuple[float, float, float]] = None, building_sim_mesh=None, building_value_name: str = 'svf_values', building_colormap: str = 'viridis', building_vmin: Optional[float] = None, building_vmax: Optional[float] = None, building_nan_color: str = 'gray', building_emissive: float = 0.0, render_voxel_buildings: bool = False, ground_sim_grid: Optional[numpy.ndarray] = None, ground_dem_grid: Optional[numpy.ndarray] = None, ground_z_offset: Optional[float] = None, ground_view_point_height: Optional[float] = None, ground_colormap: str = 'viridis', ground_vmin: Optional[float] = None, ground_vmax: Optional[float] = None, ground_emissive: float = 0.0) -> numpy.ndarray | List[str] | List[Tuple[str, str]] Visualize a VoxCity using GPU-accelerated ray tracing. This is the main entry point for GPU rendering, providing a simple interface similar to visualize_voxcity() but with GPU acceleration. :param city: The VoxCity object to visualize :type city: VoxCity :param voxel_color_map: Color mapping for voxel classes :type voxel_color_map: str or dict :param width: Output image width :type width: int :param height: Output image height :type height: int :param samples_per_pixel: Anti-aliasing quality (higher = better, slower) :type samples_per_pixel: int :param max_depth: Ray bounce depth :type max_depth: int :param camera_position: Camera position (auto-computed if None) :type camera_position: tuple, optional :param camera_look_at: Camera look-at point (auto-computed if None) :type camera_look_at: tuple, optional :param fov: Field of view in degrees :type fov: float :param output_path: Path to save the rendered image :type output_path: str, optional :param show_progress: Whether to show rendering progress :type show_progress: bool :param arch: Compute architecture ('gpu', 'cpu', 'cuda', 'vulkan', 'metal') :type arch: str :param rotation: If True, render rotating frames instead of single image :type rotation: bool :param output_directory: Directory for output frames/images :type output_directory: str :param rotation_frames: Number of frames for rotation :type rotation_frames: int :param rotation_file_prefix: Filename prefix for rotation frames :type rotation_file_prefix: str :param multi_view: If True, render standard multi-view images (isometric + orthographic) :type multi_view: bool :param multi_view_file_prefix: Filename prefix for multi-view images :type multi_view_file_prefix: str :param views: Specific views to render. Available views: - Isometric: 'iso_front_right', 'iso_front_left', 'iso_back_right', 'iso_back_left' - Orthographic: 'xy_top', 'yz_right', 'xz_front', 'yz_left', 'xz_back' If None, renders all 9 standard views. :type views: List[str], optional :param floor_enabled: Whether to render a floor plane that receives shadows (default: True) :type floor_enabled: bool :param light_direction: Light direction vector (x, y, z). Use light_direction_from_angles() for easy setup. If None, uses default southwest lighting. :type light_direction: tuple, optional :param direct: Direct light color and intensity (R, G, B) from 0.0 to 1.0. Higher values = brighter direct light. Default is (0.9, 0.9, 0.85). :type direct: tuple, optional :param ambient: Ambient light color (R, G, B) from 0.0 to 1.0. If None, uses default. :type ambient: tuple, optional :param background_color: Background color (R, G, B) from 0.0 to 1.0. If None, uses default light blue. :type background_color: tuple, optional :param building_sim_mesh: Building mesh with simulation results in metadata :type building_sim_mesh: trimesh, optional :param building_value_name: Metadata key for building values (e.g., 'svf_values', 'global', 'direct') :type building_value_name: str :param building_colormap: Matplotlib colormap for building values :type building_colormap: str :param building_vmin: Minimum value for building color scale :type building_vmin: float, optional :param building_vmax: Maximum value for building color scale :type building_vmax: float, optional :param building_nan_color: Color for NaN/invalid building values :type building_nan_color: str :param building_emissive: Emissive/luminous intensity for building simulation mesh (0=no emission, >0=glowing) :type building_emissive: float :param render_voxel_buildings: Whether to show voxel buildings with sim mesh :type render_voxel_buildings: bool :param ground_sim_grid: 2D array of ground-level simulation values (e.g., GVI, solar) :type ground_sim_grid: np.ndarray, optional :param ground_dem_grid: 2D DEM array for ground surface positioning :type ground_dem_grid: np.ndarray, optional :param ground_z_offset: Height offset for ground surface above DEM :type ground_z_offset: float, optional :param ground_view_point_height: Alternative height parameter for ground surface :type ground_view_point_height: float, optional :param ground_colormap: Matplotlib colormap for ground values :type ground_colormap: str :param ground_vmin: Minimum value for ground color scale :type ground_vmin: float, optional :param ground_vmax: Maximum value for ground color scale :type ground_vmax: float, optional :param ground_emissive: Emissive/luminous intensity for ground simulation mesh (0=no emission, >0=glowing) :type ground_emissive: float :returns: If rotation=False and multi_view=False: (H, W, 3) RGB image array If rotation=True: List of frame file paths If multi_view=True: List of (view_name, filepath) tuples :rtype: np.ndarray or List[str] or List[Tuple[str, str]] .. rubric:: Examples Simple rendering: >>> img = visualize_voxcity_gpu(city) Save to file: >>> img = visualize_voxcity_gpu(city, output_path="render.png") High quality render: >>> img = visualize_voxcity_gpu(city, samples_per_pixel=64, width=1920, height=1080) Rotation animation: >>> frames = visualize_voxcity_gpu(city, rotation=True, rotation_frames=120) Multi-view rendering (9 standard views): >>> images = visualize_voxcity_gpu(city, multi_view=True, output_directory="output") >>> for view_name, path in images: ... print(f"{view_name}: {path}") Multi-view with specific views only: >>> images = visualize_voxcity_gpu(city, multi_view=True, ... views=['iso_front_right', 'iso_front_left', 'xy_top']) With building solar irradiance: >>> building_mesh = get_building_solar_irradiance(city, ...) >>> img = visualize_voxcity_gpu(city, building_sim_mesh=building_mesh, ... building_value_name='global', building_colormap='magma') With ground-level Green View Index: >>> img = visualize_voxcity_gpu(city, ground_sim_grid=gvi_array, ground_colormap='YlGn')