-
Notifications
You must be signed in to change notification settings - Fork 40
/
camera_overscan.py
192 lines (164 loc) · 6.95 KB
/
camera_overscan.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Camera Overscan",
"author": "John Roper, Barnstorm VFX, Luca Scheller",
"version": (1, 2, 1),
"blender": (2, 80, 0),
"location": "Render Settings > Camera Overscan",
"description": "Render Overscan",
"warning": "",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Render/Camera_Overscan",
"tracker_url": "",
"category": "Render"}
import bpy
from bpy.types import (
Operator,
PropertyGroup,
)
from bpy.props import (
BoolProperty,
IntProperty,
FloatProperty,
StringProperty,
PointerProperty,
)
class CODuplicateCamera(Operator):
bl_idname = "scene.co_duplicate_camera"
bl_label = "Bake to New Camera"
bl_description = ("Make a new overscan camera with all the settings builtin\n"
"Needs an active Camera type in the Scene")
@classmethod
def poll(cls, context):
active_cam = getattr(context.scene, "camera", None)
return active_cam is not None
def execute(self, context):
active_cam = getattr(context.scene, "camera", None)
try:
if active_cam and active_cam.type == 'CAMERA':
cam_obj = active_cam.copy()
cam_obj.data = active_cam.data.copy()
cam_obj.name = "Camera_Overscan"
context.collection.objects.link(cam_obj)
except:
self.report({'WARNING'}, "Setting up a new Overscan Camera has failed")
return {'CANCELLED'}
return {'FINISHED'}
def RO_Update(self, context):
scene = context.scene
overscan = scene.camera_overscan
render_settings = scene.render
active_camera = getattr(scene, "camera", None)
active_cam = getattr(active_camera, "data", None)
# Check if there is a camera type in the scene (Object as camera doesn't work)
if not active_cam or active_camera.type not in {'CAMERA'}:
return None
if overscan.RO_Activate:
if overscan.RO_Safe_SensorSize == -1:
# Safe Property Values
overscan.RO_Safe_Res_X = render_settings.resolution_x
overscan.RO_Safe_Res_Y = render_settings.resolution_y
overscan.RO_Safe_SensorSize = active_cam.sensor_width
overscan.RO_Safe_SensorFit = active_cam.sensor_fit
if overscan.RO_Custom_Res_X == 0 or overscan.RO_Custom_Res_Y == 0:
# avoid infinite recursion on props update
if overscan.RO_Custom_Res_X != render_settings.resolution_x:
overscan.RO_Custom_Res_X = render_settings.resolution_x
if overscan.RO_Custom_Res_Y != render_settings.resolution_y:
overscan.RO_Custom_Res_Y = render_settings.resolution_y
# Reset Property Values
active_cam.sensor_width = scene.camera_overscan.RO_Safe_SensorSize
# Calc Sensor Size
active_cam.sensor_fit = 'HORIZONTAL'
sensor_size_factor = overscan.RO_Custom_Res_X / overscan.RO_Safe_Res_X
Old_SensorSize = active_cam.sensor_width
New_SensorSize = Old_SensorSize * sensor_size_factor
# Set New Property Values
active_cam.sensor_width = New_SensorSize
render_settings.resolution_x = overscan.RO_Custom_Res_X
render_settings.resolution_y = overscan.RO_Custom_Res_Y
else:
if overscan.RO_Safe_SensorSize != -1:
# Set Property Values
render_settings.resolution_x = overscan.RO_Safe_Res_X
render_settings.resolution_y = overscan.RO_Safe_Res_Y
active_cam.sensor_width = overscan.RO_Safe_SensorSize
active_cam.sensor_fit = overscan.RO_Safe_SensorFit
overscan.RO_Safe_SensorSize = -1
def RO_Menu(self, context):
scene = context.scene
overscan = scene.camera_overscan
layout = self.layout
row = layout.row()
active_cam = getattr(scene, "camera", None)
if active_cam and active_cam.type == 'CAMERA':
row.prop(overscan, 'RO_Activate', text="Use Overscan")
row_enable = row.row(align=True)
if not overscan.RO_Activate:
row_enable.enabled = False
row_enable.prop(overscan, 'RO_Custom_Res_X', text="X")
row_enable.prop(overscan, 'RO_Custom_Res_Y', text="Y")
row = layout.row()
if not overscan.RO_Activate:
row.enabled = False
row.operator("scene.co_duplicate_camera", icon="RENDER_STILL")
else:
row.label(text="No active Camera type in the Scene", icon='INFO')
class camera_overscan_props(PropertyGroup):
RO_Activate: BoolProperty(
default=False,
description="Enable/Disable Camera Overscan\n"
"Affects the active Scene Camera only\n"
"(Objects as cameras are not supported)",
update=RO_Update
)
RO_Custom_Res_X: IntProperty(
default=0,
min=0,
max=65536,
update=RO_Update
)
RO_Custom_Res_Y: IntProperty(
default=0,
min=0,
max=65536,
update=RO_Update
)
RO_Safe_Res_X: FloatProperty()
RO_Safe_Res_Y: FloatProperty()
# the hard limit is sys.max which is too much, used 65536 instead
RO_Safe_SensorSize: FloatProperty(
default=-1,
min=-1,
max=65536
)
RO_Safe_SensorFit: StringProperty()
def register():
bpy.utils.register_class(CODuplicateCamera)
bpy.utils.register_class(camera_overscan_props)
bpy.types.RENDER_PT_dimensions.append(RO_Menu)
bpy.types.Scene.camera_overscan = PointerProperty(
type=camera_overscan_props
)
def unregister():
bpy.utils.unregister_class(CODuplicateCamera)
bpy.utils.unregister_class(camera_overscan_props)
bpy.types.RENDER_PT_dimensions.remove(RO_Menu)
del bpy.types.Scene.camera_overscan
if __name__ == "__main__":
register()