Repository: Genesis-Embodied-AI/Genesis
File: genesis/vis/visualizer.py (Python)

Code before:
        self.viewer_lock = None
        self._renderer = None

    def add_camera(self, res, pos, lookat, up, model, fov, aperture, focus_dist, GUI, spp, denoise, env_idx, debug):
        cam_idx = len(self._cameras) if not debug else len(self._debug_cameras)
        camera = Camera(
            self,
            cam_idx,
            model,
            res,
            pos,
            lookat,
            up,
            fov,
            aperture,
            focus_dist,
            GUI,
            spp,
            denoise,
            env_idx=0 if debug else env_idx,
            debug=debug,
        )
        if debug:
            self._debug_cameras.append(camera)
        else:
            self._cameras.append(camera)
        return camera

    def add_light(self, pos, dir, intensity, directional, castshadow, cutoff):
        if self._batch_renderer is not None:
            self._batch_renderer.add_light(pos, dir, intensity, directional, castshadow, cutoff)
        else:
            gs.raise_exception("`add_light` is specifically for batch renderer.")

    def reset(self):
        self._t = -1

        self._context.reset()

        if self._raytracer is not None:
            self._raytracer.reset()

        if self._batch_renderer is not None:
            self._batch_renderer.reset()

        if self.viewer_lock is not None:
            if self._viewer is not None:
                self._viewer.update(auto_refresh=True)

            if self._batch_renderer is None:
                for camera in self._cameras:

Review comment (bug):
I'm not a great fan of managing cameras and "debug cameras" separately. They are inherently the same things. Just the debug camera are not considered real sensors but only used to monitor the progress of the agent / debugging. Having `camera` getting hiding debug camera by default, and keeping them accessible via `_camera` private attribute sounds sufficient for me.

Code after:
        self._renderer = None

    def add_camera(self, res, pos, lookat, up, model, fov, aperture, focus_dist, GUI, spp, denoise, env_idx, debug):
        cam_idx = len([camera for camera in self._cameras if camera.debug == debug])
        camera = Camera(
            self,
            cam_idx,
            model,
            res,
            pos,
            lookat,
            up,
            fov,
            aperture,
            focus_dist,
            GUI,
            spp,
            denoise,
            env_idx=env_idx,
            debug=debug,
        )
        self._cameras.append(camera)
        return camera

    def add_light(self, pos, dir, intensity, directional, castshadow, cutoff):
        if self._batch_renderer is not None:
            self._batch_renderer.add_light(pos, dir, intensity, directional, castshadow, cutoff)
        else:
            gs.raise_exception("`add_light` is specifically for batch renderer.")

    def reset(self):
        self._t = -1

        self._context.reset()

        if self._raytracer is not None:
            self._raytracer.reset()

        if self._batch_renderer is not None:
            self._batch_renderer.reset()

        if self.viewer_lock is not None:
            if self._viewer is not None:
                self._viewer.update(auto_refresh=True)

            if self._batch_renderer is None:
                for camera in self._cameras:
                    self._rasterizer.render_camera(camera)

    def build(self):
        self._context.build(self._scene)