-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathrenderer.py
More file actions
186 lines (135 loc) · 6.09 KB
/
renderer.py
File metadata and controls
186 lines (135 loc) · 6.09 KB
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
'''
Copyright (c) 2022 RCT Graphics Helper developers
For a complete list of all authors, please refer to the addon's meta info.
Interested in contributing? Visit https://github.com/oli414/Blender-RCT-Graphics
RCT Graphics Helper is licensed under the GNU General Public License version 3.
'''
import faulthandler
import os
import threading
import bpy
from .builders.materials_builder import MaterialsBuilder
from .palette_manager import PaletteManager
def find_material_by_name(material_name):
for mat in bpy.data.materials:
if mat.name == material_name:
return mat
return None
def find_node_by_label(tree, node_to_find):
for node in tree.nodes:
if node.label == node_to_find:
return node
return None
# Model for controlling the render settings, and starting render processes
class Renderer:
def __init__(self, context, palette_manager):
self.context = context
self.magick_path = "magick"
self.floyd_steinberg_diffusion = 35
self.palette_manager = palette_manager
self.rendering = False
self.timer = None
self.render_finished_callback = None
self.world_position_material = find_material_by_name("WorldPosition")
if self.world_position_material == None:
materials_builder = MaterialsBuilder()
materials_builder.create_world_position_material(context)
self.world_position_material = find_material_by_name(
"WorldPosition")
self.lens_shift_y_offset = round(bpy.data.cameras["Camera"].shift_y *
context.scene.render.resolution_x)
self.started_with_anti_aliasing = context.scene.render.use_antialiasing
context.scene.render.use_shadows = context.scene.rct_graphics_helper_general_properties.cast_shadows
bpy.app.handlers.render_complete.append(self._render_finished)
bpy.app.handlers.render_cancel.append(self._render_reset)
def set_dither(self, percent):
self.floyd_steinberg_diffusion = percent
# Render out the current scene
def render(self, output_still, callback):
self.render_finished_callback = callback
self._render_started()
bpy.ops.render.render(write_still=output_still) # "INVOKE_DEFAULT"
def _render_started(self):
if self.rendering:
return
print("Starting render...")
self.rendering = True
def _render_finished(self, _):
if not self.rendering:
return
print("Finished rendering")
# Start a timer before calling the callback as the render operator takes a bit to fully finish
#self.timer = threading.Timer(0.01, self._render_finished_safe)
# self.timer.start()
print("Reset renderer")
self._render_reset()
print("Call callback")
if self.render_finished_callback != None:
self.render_finished_callback()
def _render_reset(self, _=None):
if not self.rendering:
return
self.rendering = False
self.set_aa(self.started_with_anti_aliasing)
self.set_aa_with_background(False)
self.set_override_material(None)
self.set_layer("Editor")
def _render_finished_safe(self):
self.timer.cancel()
callback = self.render_finished_callback
self._render_reset()
if callback != None:
callback()
def get_palette_path(self, palette):
palette.prepare(self)
return palette.path
# Enabled or disables anti-aliasing for the next render
def set_aa(self, aa):
self.context.scene.render.use_antialiasing = aa
# Enabled or disables anti-aliasing with the background
def set_aa_with_background(self, aa_with_background):
aa_with_backgound_mix_node = find_node_by_label(
self.context.scene.node_tree, "aa_with_backgound_switch")
if aa_with_backgound_mix_node == None:
raise Exception(
"The compositing node tree does not contain a mix node for anti-aliasing with the background.")
if aa_with_background:
aa_with_backgound_mix_node.inputs[0].default_value = 1
else:
aa_with_backgound_mix_node.inputs[0].default_value = 0
# Sets the global override material that the scene is rendered with
def set_override_material(self, material):
self.context.scene.render.layers["Editor"].material_override = material
for i in range(8):
self.context.scene.render.layers["Riders {}".format(
i + 1)].material_override = material
# Sets the active render layer
def set_layer(self, layer_name):
layers = ["Editor"]
for i in range(8):
layers.append("Riders {}".format(i + 1))
for layer in layers:
self.context.scene.render.layers[layer].use = False
self.context.scene.render.layers[layer_name].use = True
input_layer_node = find_node_by_label(
self.context.scene.node_tree, "input_layer")
if input_layer_node == None:
raise Exception(
"The compositing node tree does not contain an input layer node.")
input_layer_node.layer = layer_name
def set_animation_frame(self, animation_frame_index):
self.context.scene.frame_set(animation_frame_index)
# Sets the still render output path
def set_output_path(self, path):
self.context.scene.render.filepath = path
# Sets the meta (material and tile mask) render output path
def set_meta_output_path(self, base, path):
# Find the file output node in the compositor to set the output file name and path
material_index_output_node = find_node_by_label(
self.context.scene.node_tree, "meta_output")
if material_index_output_node == None:
raise Exception(
"The compositing node tree does not contain an output node for the material index.")
# Set the file name and output path for the mask
material_index_output_node.base_path = base
material_index_output_node.file_slots[0].path = path