forked from mattebb/3delightblender
-
Notifications
You must be signed in to change notification settings - Fork 132
/
rman_engine.py
260 lines (219 loc) · 10 KB
/
rman_engine.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
import bpy
from .rfb_utils.prefs_utils import get_pref
from .rfb_utils import string_utils
from .rfb_utils import register_utils
from .rfb_logger import rfb_log
from .rman_constants import USE_GPU_MODULE
if USE_GPU_MODULE:
bgl = None
blf = None
import gpu
else:
import bgl
import blf
class PRManRender(bpy.types.RenderEngine):
bl_idname = 'PRMAN_RENDER'
bl_label = "RenderMan"
bl_use_preview = False # Turn off preview renders
bl_use_save_buffers = True
bl_use_shading_nodes = True # We support shading nodes
bl_use_shading_nodes_custom = False
bl_use_eevee_viewport = True # Use Eevee for look dev viewport mode
bl_use_postprocess = True
def __init__(self):
from . import rman_render
self.rman_render = rman_render.RmanRender.get_rman_render()
self.export_failed = None
self.ipr_already_running = False
if self.rman_render.rman_interactive_running:
# If IPR is already running, just flag it
# and don't do anything in the update methods
self.ipr_already_running = True
return
def __del__(self):
try:
from . import rman_render
except ModuleNotFoundError:
return
rr = rman_render.RmanRender.get_rman_render()
try:
if self.is_preview:
# If this was a preview render, return
return
except:
pass
if rr.rman_running:
if rr.rman_interactive_running:
rfb_log().debug("Stop interactive render.")
rr.rman_is_live_rendering = False
elif rr.is_regular_rendering():
rfb_log().debug("Stop render.")
rr.stop_render(stop_draw_thread=False)
def update(self, data, depsgraph):
pass
def view_update(self, context, depsgraph):
'''
For viewport renders. Blender calls view_update when starting viewport renders
and/or something changes in the scene.
'''
# check if we are already doing a regular render
if self.rman_render.is_regular_rendering():
return
if self.export_failed:
return
if self.ipr_already_running:
return
if self.rman_render.is_ipr_to_it():
# if we are already IPRing to "it", stop the render
self.rman_render.stop_render(stop_draw_thread=False)
# if interactive rendering has not started, start it
if not self.rman_render.rman_interactive_running and self.rman_render.sg_scene is None:
self.rman_render.bl_engine = self
self.rman_render.rman_scene.ipr_render_into = 'blender'
if not self.rman_render.start_interactive_render(context, depsgraph):
self.export_failed = True
return
self.export_failed = False
if self.rman_render.rman_interactive_running and not self.rman_render.rman_license_failed:
self.rman_render.update_scene(context, depsgraph)
def view_draw(self, context, depsgraph):
'''
For viewport renders. Blender calls view_draw whenever it redraws the 3D viewport.
This is where we check for camera moves and draw pxiels from our
Blender display driver.
'''
if self.export_failed:
return
if self.ipr_already_running:
self.draw_viewport_message(context, 'Multiple viewport rendering not supported.')
return
if self.rman_render.rman_interactive_running and not self.rman_render.rman_license_failed:
self.rman_render.update_view(context, depsgraph)
self._draw_pixels(context, depsgraph)
def _increment_version_tokens(self, external_render=False):
bl_scene = bpy.context.scene
vi = get_pref('rman_scene_version_increment', default='MANUALLY')
ti = get_pref('rman_scene_take_increment', default='MANUALLY')
if (vi == 'RENDER' and not external_render) or (vi == 'BATCH_RENDER' and external_render):
bl_scene.renderman.version_token += 1
string_utils.set_var('version', bl_scene.renderman.version_token)
if (ti == 'RENDER' and not external_render) or (ti == 'BATCH_RENDER' and external_render):
bl_scene.renderman.take_token += 1
string_utils.set_var('take', bl_scene.renderman.take_token)
def update_render_passes(self, scene=None, renderlayer=None):
# this method allows us to add our AOVs as ports to the RenderLayer node
# in the compositor.
from .rfb_utils import display_utils
if self.is_preview:
return
if self.rman_render.rman_render_into != 'blender':
return
if self.ipr_already_running:
return
self.rman_render.rman_scene.bl_scene = scene
dspy_dict = display_utils.get_dspy_dict(self.rman_render.rman_scene, include_holdouts=False)
self.register_pass(scene, renderlayer, "Combined", 4, "RGBA", 'COLOR')
for i, dspy_nm in enumerate(dspy_dict['displays'].keys()):
if i == 0:
continue
dspy = dspy_dict['displays'][dspy_nm]
dspy_chan = dspy['params']['displayChannels'][0]
chan_info = dspy_dict['channels'][dspy_chan]
chan_type = chan_info['channelType']['value']
if chan_type == 'color':
self.register_pass(scene, renderlayer, dspy_nm, 3, "RGB", 'COLOR')
elif chan_type in ['vector', 'normal', 'point']:
self.register_pass(scene, renderlayer, dspy_nm, 3, "XYZ", 'VECTOR')
else:
self.register_pass(scene, renderlayer, dspy_nm, 1, "Z", 'VALUE')
def render(self, depsgraph):
'''
Main render entry point. Blender calls this when doing final renders or preview renders.
'''
bl_scene = depsgraph.scene_eval
rm = bl_scene.renderman
baking = (rm.hider_type in ['BAKE', 'BAKE_BRICKMAP_SELECTED'])
if self.rman_render.rman_interactive_running:
# report an error if a render is trying to start while IPR is running
if self.is_preview and get_pref('rman_do_preview_renders', False):
#self.report({'ERROR'}, 'Cannot start a preview render when IPR is running')
rfb_log().debug('Cannot start a preview render when IPR is running')
pass
elif not self.is_preview:
self.report({'ERROR'}, 'Cannot start a render when IPR is running')
return
elif self.is_preview:
# double check we're not already viewport rendering
if self.rman_render.rman_interactive_running:
if get_pref('rman_do_preview_renders', False):
rfb_log().error("Cannot preview render while viewport rendering.")
return
if not get_pref('rman_do_preview_renders', False):
# user has turned off preview renders, just load the placeholder image
self.rman_render.bl_scene = depsgraph.scene_eval
#self.rman_render._load_placeholder_image()
return
if self.rman_render.rman_swatch_render_running:
return
self.rman_render.bl_engine = self
self.rman_render.start_swatch_render(depsgraph)
elif baking:
self.rman_render.bl_engine = self
if rm.enable_external_rendering:
self.rman_render.start_external_bake_render(depsgraph)
elif not self.rman_render.start_bake_render(depsgraph, for_background=bpy.app.background):
return
elif rm.enable_external_rendering:
self.rman_render.bl_engine = self
self.rman_render.start_external_render(depsgraph)
self._increment_version_tokens(external_render=True)
else:
for_background = bpy.app.background
self.rman_render.bl_engine = self
if not self.rman_render.start_render(depsgraph, for_background=for_background):
return
if not for_background:
self._increment_version_tokens(external_render=False)
def draw_viewport_message(self, context, msg):
if USE_GPU_MODULE:
return
w = context.region.width
pos_x = w / 2 - 100
pos_y = 20
blf.enable(0, blf.SHADOW)
blf.shadow_offset(0, 1, -1)
blf.shadow(0, 5, 0.0, 0.0, 0.0, 0.8)
blf.size(0, 32, 36)
blf.position(0, pos_x, pos_y, 0)
blf.color(0, 1.0, 0.0, 0.0, 1.0)
blf.draw(0, "%s" % (msg))
blf.disable(0, blf.SHADOW)
def _draw_pixels(self, context, depsgraph):
if self.rman_render.rman_license_failed:
self.draw_viewport_message(context, self.rman_render.rman_license_failed_message)
if not self.rman_render.rman_is_viewport_rendering:
return
scene = depsgraph.scene
w = context.region.width
h = context.region.height
# Bind shader that converts from scene linear to display space,
if USE_GPU_MODULE:
gpu.state.blend_set("ADDITIVE_PREMULT")
self.bind_display_space_shader(scene)
self.rman_render.draw_pixels(w, h)
self.unbind_display_space_shader()
gpu.state.blend_set("NONE")
else:
bgl.glEnable(bgl.GL_BLEND)
bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA)
self.bind_display_space_shader(scene)
self.rman_render.draw_pixels(w, h)
self.unbind_display_space_shader()
bgl.glDisable(bgl.GL_BLEND)
classes = [
PRManRender,
]
def register():
register_utils.rman_register_classes(classes)
def unregister():
register_utils.rman_unregister_classes(classes)