{
  "revision": "SIMULATOR_RENDERER_CLARIFICATION_V2",
  "created_utc": "2026-09-11T13:44:57.790586+00:00",
  "scope": "Existing source/config/artifact inspection; labels only, no scientific rerun.",
  "official_method": "https://liuwei283.github.io/RealWonder/#:~:text=Method%20Overview",
  "official_repository": "https://github.com/liuwei283/RealWonder",
  "local_release_commit": "51f5f800b87a51d2e23ac0403251e02bf3f1d29d",
  "code": [
    {
      "path": "/research/cvl-eric_jht/particle_world/src/particle_physics_data/physical_backbone_foundation_v1/external/RealWonder/demo_web/simulation_engine.py",
      "sha256": "84b968f280dd7572c341e0b4c163c7c8c982b01d2ab2ccec0f4ef8f94fcf9df2"
    },
    {
      "path": "/research/cvl-eric_jht/particle_world/src/particle_physics_data/physical_backbone_foundation_v1/realwonder_stock_v2.py",
      "sha256": "f578d5f5a1c9e45ab8676d238ffabad619d6f2ad4ed9d053d2e1a173c2be93f6"
    }
  ],
  "executed_chain": [
    "realwonder_stock_v2.main: apply case-defined actions, InteractiveSimulator.step, render_and_flow, resize/crop, save actual RGB.",
    "InteractiveSimulator.step: Genesis scene.step advances bodies; get_pos/get_quat compose current pose with inverse initial transform and move saved foreground points.",
    "_MinimalSVR.update_fg_obj_info: replace point coordinates; preserve their saved color features.",
    "_MinimalSVR.render: PyTorch3D PointsRasterizer and AlphaCompositor render foreground colors and combine with a cached colored-point background.",
    "RealWonderBaseline.generate: render RGB enters VAE; NoiseWarper.process(input_flow=False) derives RAFT-warped noise; released neural generator produces final RGB."
  ],
  "scene_configs": {
    "lamp": {
      "binding": {
        "path": "/research/cvl-eric_jht/particle_world/runs/integration/realwonder_pipeline_comparison_v1/review/assets/lamp/rw_CONDITION_RESULT.json",
        "sha256": "8bc6ea1e6f0f9ae1ea5d48b2d032ed38c999f7281d27c3c7fded460ecb1ad6a2"
      },
      "material_type": [
        "rigid"
      ],
      "use_primitive": true,
      "debug": false
    },
    "persimmon": {
      "binding": {
        "path": "/research/cvl-eric_jht/particle_world/runs/integration/realwonder_pipeline_comparison_v1/review/assets/persimmon/rw_CONDITION_RESULT.json",
        "sha256": "605ce0179937c11099b4c2d67ee898453fca13fee51de9041c4675f48fe98242"
      },
      "material_type": [
        "rigid",
        "rigid",
        "rigid"
      ],
      "use_primitive": false,
      "debug": false
    }
  },
  "rigid_vs_particles": "Both selected scenes use rigid dynamics. The rendered colored samples are moved by rigid pose transforms, not independent particle dynamics. Other supported nonrigid source branches use solver particles, but were not executed for these scenes.",
  "why_input_like": "Reconstructed foreground color samples and saved background appearance are reused while coordinates move. This is a coarse appearance-preserving render, not copied original frames and not the neural generated output.",
  "raw_genesis_debug_view": "NOT_PERSISTED: executed config debug=false, so the Genesis debug camera was not created. setup.png is a diagnostic visualization of saved bridge meshes/poses/center paths, not a native Genesis screenshot.",
  "geometry_scope": "Lamp collision proxy is a box; persimmon uses rigid meshes. Rendered appearance uses prepared colored point surfaces. Watertight collision/display mesh does not ensure full unseen texture coverage.",
  "code_excerpts": [
    {
      "function": "InteractiveSimulator.step",
      "line": 324,
      "text": "    def step(self, extract_points=True):\n        \"\"\"Run one simulation step with interactive force applied.\"\"\"\n        if self.demo_case_handler is not None:\n            self.demo_case_handler.apply_forces(self, self.step_count)\n\n        if self.debug_cam is not None and not self._debug_cam_failed:\n            try:\n                self.debug_cam.start_recording()\n            except Exception:\n                self._debug_cam_failed = True\n\n        self.scene.step()\n\n        if self.debug_cam is not None and not self._debug_cam_failed:\n            try:\n                render_out = self.debug_cam.render()\n                cv2.imwrite(\n                    str(self._debug_gs_frames / f\"{self.step_count:04d}.png\"),\n                    render_out[0],\n                )\n            except Exception:\n                self._debug_cam_failed = True\n\n        self.step_count += 1\n\n        if not extract_points:\n            return None\n\n        updated_all_obj_points = []\n        for obj_idx, mt in enumerate(self.material_type):\n            if mt == \"rigid\":\n                pos = self.objs[obj_idx].get_pos().cpu().numpy()\n                quat = self.objs[obj_idx].get_quat().cpu().numpy()\n                T = torch.from_numpy(\n                    pose_to_transform_matrix(pos, quat)\n                ).to(self.device).float()\n                T_inv = torch.linalg.inv(self.initial_transform_matrix[obj_idx])\n                real_T = T @ T_inv\n                pts_h = torch.cat([\n                    self.fg_pcs_gs[obj_idx][\"points\"],\n                    torch.ones(self.fg_pcs_gs[obj_idx][\"points\"].shape[0], 1, device=self.device),\n                ], dim=1)\n                updated = (real_T.unsqueeze(0) @ pts_h.unsqueeze(-1)).squeeze(-1)[:, :3]\n                updated_all_obj_points.append(gs_to_pt3d(updated))\n            else:\n                p_start = self.objs[obj_idx].particle_start\n                p_end = self.objs[obj_idx].particle_end\n                state = self.objs[obj_idx].solver.get_state(0)\n                particles_now = state.pos[0, p_start:p_end].float()\n\n                init_particles_gpu = self._init_particles_gpu.get(obj_idx)\n                if init_particles_gpu is None:\n                    init_particles_gpu = torch.tensor(\n                        self.objs[obj_idx].init_particles,\n                        device=self.device, dtype=torch.float32,\n                    )\n                delta = particles_now - init_particles_gpu\n                pc_delta = delta[self.closest_indices[obj_idx]].mean(dim=1)\n                updated = self.fg_pcs_gs[obj_idx][\"points\"] + pc_delta\n                updated_all_obj_points.append(gs_to_pt3d(updated))\n\n        return updated_all_obj_points"
    },
    {
      "function": "_MinimalSVR.update_fg_obj_info",
      "line": 622,
      "text": "    def update_fg_obj_info(self, all_obj_points):\n        for idx, pts in enumerate(all_obj_points):\n            self.fg_pcs[idx][\"points\"] = pts.clone()"
    },
    {
      "function": "_MinimalSVR.render",
      "line": 671,
      "text": "    def render(self, render_bg=True, render_obj=True, render_mesh=True,\n               frame_id=0, save=False, mask=True, compute_optical_flow=True):\n        from pytorch3d.structures import Pointclouds\n        from torchvision.transforms import ToPILImage\n\n        cameras = self.current_camera\n        image_size = self.target_size[0]\n\n        # Background (cached after first render)\n        if render_bg and self.cache_bg is None:\n            from pytorch3d.renderer import (\n                PointsRenderer, PointsRasterizer, PointsRasterizationSettings,\n                AlphaCompositor,\n            )\n            bg_pc = Pointclouds(\n                points=[self.bg_points], features=[self.bg_points_colors],\n            )\n            bg_raster_settings = PointsRasterizationSettings(\n                image_size=image_size,\n                radius=self.config.get('bg_points_render_radius', 0.0001),\n                points_per_pixel=30,\n            )\n            bg_renderer = PointsRenderer(\n                rasterizer=PointsRasterizer(\n                    cameras=cameras, raster_settings=bg_raster_settings,\n                ),\n                compositor=AlphaCompositor(),\n            )\n            self.cache_bg = bg_renderer(bg_pc)\n\n        if render_bg and self.cache_bg is not None:\n            bg_image = self.cache_bg\n        else:\n            bg_image = torch.zeros(1, image_size, image_size, 3, device=self.device)\n\n        base_rgb = bg_image[0].clone()\n        final_rgb = base_rgb.clone()\n\n        # Foreground\n        all_fg_points = []\n        all_fg_colors = []\n        for pc_info in self.fg_pcs:\n            all_fg_points.append(pc_info['points'])\n            all_fg_colors.append(pc_info['colors'])\n\n        combined_fg_points = torch.cat(all_fg_points, dim=0)\n        combined_fg_colors = torch.cat(all_fg_colors, dim=0)\n        flow_rendered_points = combined_fg_points.clone()\n\n        combined_rgba = torch.cat([\n            combined_fg_colors,\n            torch.ones_like(combined_fg_colors[..., :1]),\n        ], dim=-1)\n\n        fg_pc = Pointclouds(points=[combined_fg_points], features=[combined_rgba])\n\n        fragments = self._fg_rasterizer(fg_pc)\n        r = self._fg_rasterizer.raster_settings.radius\n        dists2 = fragments.dists.permute(0, 3, 1, 2)\n        weights = 1 - dists2 / (r * r)\n        fg_image = self._fg_renderer.compositor(\n            fragments.idx.long().permute(0, 3, 1, 2),\n            weights,\n            fg_pc.features_packed().permute(1, 0),\n        )\n        fg_image = fg_image.permute(0, 2, 3, 1)\n        fg_rgb = fg_image[0, ..., :3]\n        fg_alpha = fg_image[0, ..., 3:4]\n        fg_depth = fragments.zbuf[0, ..., 0]\n\n        fg_points_mask = torch.where(\n            fg_alpha.squeeze(-1) > self.config['alpha_threshold'], 1.0, 0.0,\n        ).unsqueeze(-1)\n        fg_mask_2d = fg_points_mask.squeeze(-1)\n        final_rgb = fg_rgb * fg_mask_2d.unsqueeze(-1) + final_rgb * (1.0 - fg_mask_2d.unsqueeze(-1))\n\n        # Mesh\n        mesh_mask = torch.zeros(image_size, image_size, 1, dtype=torch.float32, device=self.device)\n\n        if render_mesh and self.franka_mesh is not None:\n            from pytorch3d.renderer import ("
    }
  ],
  "scientific_outputs_modified": false,
  "new_GPU_or_simulation_or_inference": false
}
