Shot Viewer: sequence field, cameras named CAM_sq0000_sh0000
The Shot Viewer panel gets a Sequence number, saved with the scene. New
shot cameras are named from it with SHOT_CAMERA_NAME_FORMAT
("{prefix}{sequence}_{shot}") and SEQUENCE_NAME_FORMAT ("sq{:04d}"),
both overridable in the config JSON.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c376a92591
commit
00788bb3bf
4 files changed
+44
-8
No files matched your search
@@ -254,6 +254,10 @@ Choosing a shot in the panel moves the playhead to it and puts **the 3D view you
|
|||||||
|
|
||||||
The list always highlights the shot under the playhead. The file does not need any shots yet: add the first one with **+**.
|
The list always highlights the shot under the playhead. The file does not need any shots yet: add the first one with **+**.
|
||||||
|
|
||||||
|
### Sequence
|
||||||
|
|
||||||
|
Set the sequence number in the **Sequence** field at the top of the panel. It is saved with the scene, and the formatted name is shown next to it (`10` → `sq0010`). It is used to name the cameras of new shots: `CAM_sq0010_sh0030`. Both formats can be changed in the [Configuration](#configuration) (`SEQUENCE_NAME_FORMAT`, `SHOT_CAMERA_NAME_FORMAT`).
|
||||||
|
|
||||||
### Moving through the sequence
|
### Moving through the sequence
|
||||||
|
|
||||||
| To… | Do… |
|
| To… | Do… |
|
||||||
@@ -275,7 +279,7 @@ Click **+** next to the shot list:
|
|||||||
|---|---|
|
|---|---|
|
||||||
| **Name** | Pre-filled with the next free shot number (`sh0010`, `sh0020`…). This is the marker name. |
|
| **Name** | Pre-filled with the next free shot number (`sh0010`, `sh0020`…). This is the marker name. |
|
||||||
| **Duration** | Length of the shot in frames. |
|
| **Duration** | Length of the shot in frames. |
|
||||||
| **New Camera** | On: creates the camera `CAM_<shot name>`, copying the lens and position of the current camera, so you start from the current framing. Off: pick an existing camera of the scene. |
|
| **New Camera** | On: creates the camera `CAM_<sequence>_<shot>` (its name is shown in the dialog), copying the lens and position of the current camera, so you start from the current framing. Off: pick an existing camera of the scene. |
|
||||||
|
|
||||||
The shot is added at the end of the sequence and the scene's **End** frame grows to include it. The first shot starts at frame 1001, and the scene **Start** moves there too. The playhead and the 3D view then jump to the new shot.
|
The shot is added at the end of the sequence and the scene's **End** frame grows to include it. The first shot starts at frame 1001, and the scene **Start** moves there too. The playhead and the 3D view then jump to the new shot.
|
||||||
|
|
||||||
@@ -316,6 +320,7 @@ To change them **without editing the code**, write a JSON file with the keys to
|
|||||||
"RESOLUTION": [1920, 1080],
|
"RESOLUTION": [1920, 1080],
|
||||||
"RENAME_SIDES": ["center", "left", "right"],
|
"RENAME_SIDES": ["center", "left", "right"],
|
||||||
"SHOT_FRAME_START": 1001,
|
"SHOT_FRAME_START": 1001,
|
||||||
|
"SEQUENCE_NAME_FORMAT": "sq{:03d}",
|
||||||
"SHOT_VIEWER_RIG_GROUPS": {
|
"SHOT_VIEWER_RIG_GROUPS": {
|
||||||
"Characters": "(?i)^(?:chr|ch)[_-]"
|
"Characters": "(?i)^(?:chr|ch)[_-]"
|
||||||
}
|
}
|
||||||
@@ -324,6 +329,8 @@ To change them **without editing the code**, write a JSON file with the keys to
|
|||||||
|
|
||||||
Unknown keys are ignored and reported in the system console.
|
Unknown keys are ignored and reported in the system console.
|
||||||
|
|
||||||
|
Name formats use Python's `str.format`: `"sq{:04d}"` turns `10` into `sq0010`. `SHOT_CAMERA_NAME_FORMAT` takes the named tokens `{prefix}` (the camera prefix of `OBJECT_PREFIXES`, `CAM_`), `{sequence}` and `{shot}`. The default `"{prefix}{sequence}_{shot}"` gives `CAM_sq0010_sh0030`.
|
||||||
|
|
||||||
### Keys by tool
|
### Keys by tool
|
||||||
|
|
||||||
| Tool | Keys |
|
| Tool | Keys |
|
||||||
@@ -336,7 +343,7 @@ Unknown keys are ignored and reported in the system console.
|
|||||||
| Sanity Check: layout | `SET_COLLECTION_PATTERN` |
|
| Sanity Check: layout | `SET_COLLECTION_PATTERN` |
|
||||||
| Sanity Check: panel | `CATEGORY_ORDER`, `MAX_ISSUES_DRAWN` |
|
| Sanity Check: panel | `CATEGORY_ORDER`, `MAX_ISSUES_DRAWN` |
|
||||||
| Rename | `RENAME_SEPARATOR`, `RENAME_PADDING`, `RENAME_SIDES`, `RENAME_TYPE_SUFFIXES` (plus `OBJECT_PREFIXES` / `DATABLOCK_PREFIXES` for *By Type* prefixes) |
|
| Rename | `RENAME_SEPARATOR`, `RENAME_PADDING`, `RENAME_SIDES`, `RENAME_TYPE_SUFFIXES` (plus `OBJECT_PREFIXES` / `DATABLOCK_PREFIXES` for *By Type* prefixes) |
|
||||||
| Shot Viewer | `SHOT_VIEWER_RIG_GROUPS`, `SHOT_NAME_FORMAT`, `SHOT_NUMBER_STEP`, `SHOT_FRAME_START`, `SHOT_DEFAULT_DURATION` |
|
| Shot Viewer | `SHOT_VIEWER_RIG_GROUPS`, `SHOT_NAME_FORMAT`, `SHOT_NUMBER_STEP`, `SHOT_FRAME_START`, `SHOT_DEFAULT_DURATION`, `SEQUENCE_NAME_FORMAT`, `SHOT_CAMERA_NAME_FORMAT` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -246,6 +246,11 @@ SHOT_VIEWER_RIG_GROUPS = {
|
|||||||
|
|
||||||
# Shots added by the shot viewer. TODO: confirm with production.
|
# Shots added by the shot viewer. TODO: confirm with production.
|
||||||
SHOT_NAME_FORMAT = "sh{:04d}"
|
SHOT_NAME_FORMAT = "sh{:04d}"
|
||||||
|
# Sequence of the scene (number set in the Shot Viewer panel): SEQUENCE_NAME_FORMAT.format(number).
|
||||||
|
SEQUENCE_NAME_FORMAT = "sq{:04d}"
|
||||||
|
# Cameras added by the shot viewer. Tokens: {prefix} (OBJECT_PREFIXES["CAMERA"]),
|
||||||
|
# {sequence} (SEQUENCE_NAME_FORMAT) and {shot} (the shot name).
|
||||||
|
SHOT_CAMERA_NAME_FORMAT = "{prefix}{sequence}_{shot}"
|
||||||
SHOT_NUMBER_STEP = 10
|
SHOT_NUMBER_STEP = 10
|
||||||
SHOT_FRAME_START = 1001
|
SHOT_FRAME_START = 1001
|
||||||
SHOT_DEFAULT_DURATION = 48
|
SHOT_DEFAULT_DURATION = 48
|
||||||
|
|||||||
+26
-6
@@ -110,16 +110,27 @@ def next_shot_name(scene):
|
|||||||
return config.SHOT_NAME_FORMAT.format((max(numbers, default=0) // step + 1) * step)
|
return config.SHOT_NAME_FORMAT.format((max(numbers, default=0) // step + 1) * step)
|
||||||
|
|
||||||
|
|
||||||
def _new_camera(scene, name, source=None):
|
def sequence_name(scene):
|
||||||
|
return config.SEQUENCE_NAME_FORMAT.format(scene.wtd_sequence)
|
||||||
|
|
||||||
|
|
||||||
|
def camera_name(scene, shot):
|
||||||
|
"""Name of a new shot camera (config SHOT_CAMERA_NAME_FORMAT)."""
|
||||||
|
return config.SHOT_CAMERA_NAME_FORMAT.format(
|
||||||
|
prefix=config.OBJECT_PREFIXES.get("CAMERA", ""), sequence=sequence_name(scene), shot=shot
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _new_camera(scene, shot, source=None):
|
||||||
"""New camera in the scene collection, copying ``source`` (lens and placement) when given."""
|
"""New camera in the scene collection, copying ``source`` (lens and placement) when given."""
|
||||||
camera_name = config.OBJECT_PREFIXES.get("CAMERA", "") + name
|
name = camera_name(scene, shot)
|
||||||
if source is not None and source.type == "CAMERA":
|
if source is not None and source.type == "CAMERA":
|
||||||
data = source.data.copy()
|
data = source.data.copy()
|
||||||
data.name = camera_name
|
data.name = name
|
||||||
else:
|
else:
|
||||||
source = None
|
source = None
|
||||||
data = bpy.data.cameras.new(camera_name)
|
data = bpy.data.cameras.new(name)
|
||||||
camera = bpy.data.objects.new(camera_name, data)
|
camera = bpy.data.objects.new(name, data)
|
||||||
if source is not None:
|
if source is not None:
|
||||||
camera.matrix_world = source.matrix_world.copy()
|
camera.matrix_world = source.matrix_world.copy()
|
||||||
else:
|
else:
|
||||||
@@ -231,7 +242,10 @@ class WTD_OT_shot_viewer_new_shot(bpy.types.Operator):
|
|||||||
layout.prop(self, "name")
|
layout.prop(self, "name")
|
||||||
layout.prop(self, "duration")
|
layout.prop(self, "duration")
|
||||||
layout.prop(self, "new_camera")
|
layout.prop(self, "new_camera")
|
||||||
if not self.new_camera:
|
if self.new_camera:
|
||||||
|
name = self.name.strip() or next_shot_name(context.scene)
|
||||||
|
layout.label(text=camera_name(context.scene, name), icon="CAMERA_DATA")
|
||||||
|
else:
|
||||||
layout.prop_search(self, "camera_name", context.scene, "objects", icon="CAMERA_DATA")
|
layout.prop_search(self, "camera_name", context.scene, "objects", icon="CAMERA_DATA")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
@@ -358,12 +372,18 @@ def register():
|
|||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
bpy.types.WindowManager.wtd_shot_viewer = PointerProperty(type=WTD_ShotViewerSettings)
|
bpy.types.WindowManager.wtd_shot_viewer = PointerProperty(type=WTD_ShotViewerSettings)
|
||||||
|
bpy.types.Scene.wtd_sequence = IntProperty(
|
||||||
|
name="Sequence",
|
||||||
|
description="Sequence number of the scene, used in the names of new cameras (config SEQUENCE_NAME_FORMAT)",
|
||||||
|
min=0,
|
||||||
|
)
|
||||||
bpy.app.handlers.frame_change_post.append(_on_frame_change)
|
bpy.app.handlers.frame_change_post.append(_on_frame_change)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
if _on_frame_change in bpy.app.handlers.frame_change_post:
|
if _on_frame_change in bpy.app.handlers.frame_change_post:
|
||||||
bpy.app.handlers.frame_change_post.remove(_on_frame_change)
|
bpy.app.handlers.frame_change_post.remove(_on_frame_change)
|
||||||
|
del bpy.types.Scene.wtd_sequence
|
||||||
del bpy.types.WindowManager.wtd_shot_viewer
|
del bpy.types.WindowManager.wtd_shot_viewer
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
@@ -283,6 +283,10 @@ class _ShotViewerPanel:
|
|||||||
scene = context.scene
|
scene = context.scene
|
||||||
has_shots = bool(shot_viewer.shots(scene))
|
has_shots = bool(shot_viewer.shots(scene))
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(scene, "wtd_sequence")
|
||||||
|
row.label(text=shot_viewer.sequence_name(scene))
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.scale_y = 1.4
|
row.scale_y = 1.4
|
||||||
row.enabled = has_shots
|
row.enabled = has_shots
|
||||||
|
|||||||
Reference in new issue
Block a user