1 |
""" |
2 |
@author: John NGUI |
3 |
""" |
4 |
|
5 |
import vtk |
6 |
from constant import Renderer, Color, Viewport |
7 |
|
8 |
class Scene: |
9 |
""" |
10 |
Class that defines a scene. A scene is a window in which objects are to |
11 |
be rendered on. Only one scene needs to be created. However, a scene may |
12 |
be divided into four smaller windows called viewports (if needed). |
13 |
Each viewport can render a different object. |
14 |
""" |
15 |
|
16 |
def __init__(self, renderer = Renderer.ONLINE, num_viewport = 1, |
17 |
x_size = 1152, y_size = 864): |
18 |
""" |
19 |
Initialise the scene. |
20 |
|
21 |
@type renderer: L{Renderer <constant.Renderer>} constant |
22 |
@param renderer: Type of renderer |
23 |
@type num_viewport: Number |
24 |
@param num_viewport: Number of viewport(s) in the scene. Either 1 or 4 |
25 |
@type x_size: Number |
26 |
@param x_size: Size of the render window along the x-axis |
27 |
@type y_size: Number |
28 |
@param y_size: Size of the render window along the y-axis |
29 |
""" |
30 |
|
31 |
self.__renderer = renderer |
32 |
self.__num_viewport = num_viewport |
33 |
self.__x_size = x_size |
34 |
self.__y_size = y_size |
35 |
|
36 |
self.__OFFLINE = "offline" |
37 |
self.__JPG = "jpg" |
38 |
self.__BMP = "bmp" |
39 |
self.__PNM = "pnm" |
40 |
self.__PNG = "png" |
41 |
self.__TIF = "tif" |
42 |
self.__PS = "ps" |
43 |
|
44 |
self.__vtk_render_window = vtk.vtkRenderWindow() |
45 |
self.__setupScene() |
46 |
|
47 |
def __setupScene(self): |
48 |
""" |
49 |
Setup the scene. |
50 |
""" |
51 |
|
52 |
self.__createViewport() |
53 |
self.__addRenderer() |
54 |
self.setBackground(Color.WHITE) # Default background color is white. |
55 |
|
56 |
# Default title bar. |
57 |
self.setTitleBar("Earth Systems Science Computational Centre (ESSCC)") |
58 |
self.__setSize(self.__x_size, self.__y_size) |
59 |
|
60 |
# True for Online rendering. |
61 |
if(self.__renderer.startswith(Renderer.ONLINE)): |
62 |
self.__setupOnlineRendering() |
63 |
# True for all Online renderers except Renderer.ONLINE. |
64 |
if(self.__renderer != Renderer.ONLINE): |
65 |
self.__setupWindowToImage() |
66 |
# True for Offline rendering. |
67 |
elif(self.__renderer.startswith(self.__OFFLINE)): |
68 |
self.__setupOfflineRendering() |
69 |
self.__setupWindowToImage() |
70 |
# True for Display rendering. |
71 |
elif(self.__renderer.startswith(Renderer.DISPLAY)): |
72 |
# True for all Display renderers except Renderer.DISPLAY. |
73 |
if(self.__renderer != Renderer.DISPLAY): |
74 |
self.__setupWindowToImage() |
75 |
|
76 |
def __createViewport(self): |
77 |
""" |
78 |
Create the viewport(s) in the scene. |
79 |
""" |
80 |
|
81 |
# Create the renderer(s) for the viewport(s). |
82 |
self.__vtk_renderer = [] |
83 |
for viewport in range(0, self.__num_viewport): |
84 |
self.__vtk_renderer.append(vtk.vtkRenderer()) |
85 |
|
86 |
if(self.__num_viewport == 4): |
87 |
# Renderer for the entire scene (background). |
88 |
self.__vtk_renderer_background = vtk.vtkRenderer() |
89 |
|
90 |
# Specify the positioning of the four viewports (between 0 and 1). |
91 |
self.__vtk_renderer[Viewport.SOUTH_WEST].SetViewport( |
92 |
0.0, 0.0, 0.5, 0.5) |
93 |
self.__vtk_renderer[Viewport.NORTH_WEST].SetViewport( |
94 |
0.0, 0.5013, 0.5, 1) |
95 |
self.__vtk_renderer[Viewport.NORTH_EAST].SetViewport( |
96 |
0.501, 0.5013, 1, 1) |
97 |
self.__vtk_renderer[Viewport.SOUTH_EAST].SetViewport( |
98 |
0.501, 0.0, 1.0, 0.5) |
99 |
|
100 |
def setBackground(self, color): |
101 |
""" |
102 |
Set the background color of the scene. |
103 |
|
104 |
@type color: L{Color <constant.Color>} constant |
105 |
@param color: Scene background color |
106 |
""" |
107 |
|
108 |
# Color the entire scene (background) black initially. |
109 |
# This is carried out mainly to have the borders between |
110 |
# the viewports visibly black. |
111 |
if(self.__num_viewport == 4): |
112 |
self.__vtk_renderer_background.SetBackground(Color.BLACK) |
113 |
|
114 |
for viewport in range(0, self.__num_viewport): |
115 |
self.__vtk_renderer[viewport].SetBackground(color) |
116 |
|
117 |
def __addRenderer(self): |
118 |
""" |
119 |
Add the renderer(s) to the render window. |
120 |
""" |
121 |
|
122 |
# Add the renderer for the black scene (background). |
123 |
if(self.__num_viewport == 4): |
124 |
self.__vtk_render_window.AddRenderer( |
125 |
self.__vtk_renderer_background) |
126 |
|
127 |
for viewport in range(0, self.__num_viewport): |
128 |
self.__vtk_render_window.AddRenderer(self.__vtk_renderer[viewport]) |
129 |
|
130 |
def setTitleBar(self, text): |
131 |
""" |
132 |
Set the text on the title bar of the render window. |
133 |
|
134 |
@type text: String |
135 |
@param text: Text on the title bar |
136 |
""" |
137 |
|
138 |
self.__vtk_render_window.SetWindowName(text) |
139 |
|
140 |
def __setSize(self, x_size, y_size): |
141 |
""" |
142 |
Set the size of the render window. |
143 |
|
144 |
@type x_size: Number |
145 |
@param x_size: Size of the render window along the x-axis |
146 |
@type y_size: Number |
147 |
@param y_size: Size of the render window along the y-axis |
148 |
""" |
149 |
|
150 |
self.__vtk_render_window.SetSize(x_size, y_size) |
151 |
|
152 |
def __setupOnlineRendering(self): |
153 |
""" |
154 |
Setup the window interactor for online rendering. |
155 |
""" |
156 |
|
157 |
# Associate the window interactor with the render window. |
158 |
self.__vtk_render_window_interactor = vtk.vtkRenderWindowInteractor() |
159 |
self.__vtk_render_window_interactor.SetRenderWindow( |
160 |
self.__vtk_render_window) |
161 |
self.__vtk_render_window_interactor.Initialize() |
162 |
|
163 |
def __setupOfflineRendering(self): |
164 |
""" |
165 |
Enables the offline rendering (no window comes up). |
166 |
""" |
167 |
|
168 |
# Enables the offscreen rendering. |
169 |
self.__vtk_render_window.OffScreenRenderingOn() |
170 |
|
171 |
def __setupWindowToImage(self): |
172 |
""" |
173 |
Setup the window to image filter to convert the output from the render |
174 |
window into an image. |
175 |
""" |
176 |
|
177 |
self.__vtk_window_to_image = vtk.vtkWindowToImageFilter() |
178 |
self.__vtk_window_to_image.SetInput(self.__vtk_render_window) |
179 |
self.__vtk_image_writer = self.__getImageWriter() |
180 |
|
181 |
def __getImageWriter(self): |
182 |
""" |
183 |
Return the appropriate image writer based on the specified renderer. |
184 |
|
185 |
@rtype: vtkImageWriter |
186 |
@return: Image writer |
187 |
""" |
188 |
|
189 |
if(self.__renderer.endswith(self.__JPG)): |
190 |
return vtk.vtkJPEGWriter() |
191 |
elif(self.__renderer.endswith(self.__BMP)): |
192 |
return vtk.vtkBMPWriter() |
193 |
elif(self.__renderer.endswith(self.__PNM)): |
194 |
return vtk.vtkPNMWriter() |
195 |
elif(self.__renderer.endswith(self.__PNG)): |
196 |
return vtk.vtkPNGWriter() |
197 |
elif(self.__renderer.endswith(self.__TIF)): |
198 |
return vtk.vtkTIFFWriter() |
199 |
elif(self.__renderer.endswith(self.__PS)): |
200 |
return vtk.vtkPostScriptWriter() |
201 |
|
202 |
def __saveImage(self, image_name): |
203 |
""" |
204 |
Save the rendered object as an image. |
205 |
|
206 |
@type image_name: String |
207 |
@param image_name: Name of the saved image. |
208 |
""" |
209 |
|
210 |
# NOTE: Render and Modified must be called everytime before writing |
211 |
# an image. Otherwise, only the first image will always be saved. |
212 |
# This is due to the architecture of VTK. |
213 |
self.__vtk_render_window.Render() |
214 |
self.__vtk_window_to_image.Modified() |
215 |
|
216 |
# Retrieve the rendered object from the window and convert it into an |
217 |
# image. |
218 |
self.__vtk_image_writer.SetInput( |
219 |
self.__vtk_window_to_image.GetOutput()) |
220 |
self.__vtk_image_writer.SetFileName(image_name) |
221 |
self.__vtk_image_writer.Write() |
222 |
|
223 |
def __animate(self): |
224 |
""" |
225 |
Animate the rendered object on-the-fly. |
226 |
""" |
227 |
|
228 |
# With Render() ONLY, the rendered object is animated onto the |
229 |
# scene on-the-fly and no interaction can occur. |
230 |
self.__vtk_render_window.Render() |
231 |
|
232 |
def render(self, image_name = None): |
233 |
""" |
234 |
Render the object using either the online, offline or display mode. |
235 |
""" |
236 |
|
237 |
self.__vtk_render_window.Render() |
238 |
|
239 |
if(self.__renderer.startswith(Renderer.ONLINE)): |
240 |
# NOTE: Once Start() is executed, the driver will not further |
241 |
# execute any subsequent codes thereafter unless the 'q' or |
242 |
# 'e' keys are pressed. |
243 |
self.__vtk_render_window_interactor.Start() |
244 |
|
245 |
# True for all online renderers except Renderer.ONLINE. |
246 |
if(self.__renderer != Renderer.ONLINE): |
247 |
self.__saveImage(image_name) |
248 |
# True for all display renderers except Renderer.DISPLAY. |
249 |
elif(self.__renderer.startswith(self.__OFFLINE) or |
250 |
self.__renderer != Renderer.DISPLAY): |
251 |
self.__saveImage(image_name) |
252 |
|
253 |
def _addActor3D(self, viewport, actor): |
254 |
""" |
255 |
Add the actor3D to the appropriate viewport. |
256 |
|
257 |
@type viewport: L{Viewport <constant.Viewport>} constant |
258 |
@param viewport: Viewport in which the actor3D is to be added to |
259 |
@type actor: vtkActor |
260 |
@param actor: Actor3D which is to be added to the viewport |
261 |
""" |
262 |
|
263 |
self.__vtk_renderer[viewport].AddActor(actor) |
264 |
|
265 |
def _addActor2D(self, viewport, actor): |
266 |
""" |
267 |
Add the actor2D to the appropriate viewport. |
268 |
|
269 |
@type viewport: L{Viewport <constant.Viewport>} constant |
270 |
@param viewport: Viewport in which the actor2D is to be added to |
271 |
@type actor: vtkActor2D |
272 |
@param actor: Actor2D which is to be added to the viewport |
273 |
""" |
274 |
|
275 |
self.__vtk_renderer[viewport].AddActor2D(actor) |
276 |
|
277 |
def _setActiveCamera(self, viewport, camera): |
278 |
""" |
279 |
Set the camera to the appropriate viewport. |
280 |
|
281 |
@type viewport: L{Viewport <constant.Viewport>} constant |
282 |
@param viewport: Viewport in which the camera is to be added to |
283 |
@type camera: vtkCamera |
284 |
@param camera: Camera which is to be assigned to the viewport |
285 |
""" |
286 |
|
287 |
self.__vtk_renderer[viewport].SetActiveCamera(camera) |
288 |
|
289 |
def _addLight(self, viewport, light): |
290 |
""" |
291 |
Add the light to the appropriate viewport. |
292 |
|
293 |
@type viewport: L{Viewport <constant.Viewport>} constant |
294 |
@param viewport: Viewport in which the camera is to be added to |
295 |
@type light: vtkLight |
296 |
@param light: Light which is to be assigned to the viewport |
297 |
""" |
298 |
|
299 |
self.__vtk_renderer[viewport].AddLight(light) |
300 |
|
301 |
def _getRenderer(self): |
302 |
""" |
303 |
Return the renderer(s) |
304 |
|
305 |
@rtype: List |
306 |
@return: A list of renderer(s) |
307 |
""" |
308 |
|
309 |
return self.__vtk_renderer |
310 |
|