Blender V4.3
cycles_standalone.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <stdio.h>
6
7#include "device/device.h"
8#include "scene/camera.h"
9#include "scene/integrator.h"
10#include "scene/scene.h"
11#include "session/buffers.h"
12#include "session/session.h"
13
14#include "util/args.h"
15#include "util/foreach.h"
16#include "util/function.h"
17#include "util/image.h"
18#include "util/log.h"
19#include "util/path.h"
20#include "util/progress.h"
21#include "util/string.h"
22#include "util/time.h"
23#include "util/transform.h"
24#include "util/unique_ptr.h"
25#include "util/version.h"
26
27#ifdef WITH_USD
28# include "hydra/file_reader.h"
29#endif
30
31#include "app/cycles_xml.h"
33
34#ifdef WITH_CYCLES_STANDALONE_GUI
36# include "opengl/window.h"
37#endif
38
40
53
54static void session_print(const string &str)
55{
56 /* print with carriage return to overwrite previous */
57 printf("\r%s", str.c_str());
58
59 /* add spaces to overwrite longer previous print */
60 static int maxlen = 0;
61 int len = str.size();
62 maxlen = max(len, maxlen);
63
64 for (int i = len; i < maxlen; i++) {
65 printf(" ");
66 }
67
68 /* flush because we don't write an end of line */
69 fflush(stdout);
70}
71
73{
74 string status, substatus;
75
76 /* get status */
77 double progress = options.session->progress.get_progress();
78 options.session->progress.get_status(status, substatus);
79
80 if (substatus != "") {
81 status += ": " + substatus;
82 }
83
84 /* print status */
85 status = string_printf("Progress %05.2f %s", (double)progress * 100, status.c_str());
86 session_print(status);
87}
88
90{
91 static BufferParams buffer_params;
92 buffer_params.width = options.width;
93 buffer_params.height = options.height;
94 buffer_params.full_width = options.width;
95 buffer_params.full_height = options.height;
96
97 return buffer_params;
98}
99
100static void scene_init()
101{
103
104 /* Read XML or USD */
105#ifdef WITH_USD
107 HD_CYCLES_NS::HdCyclesFileReader::read(options.session, options.filepath.c_str());
108 }
109 else
110#endif
111 {
113 }
114
115 /* Camera width/height override? */
116 if (!(options.width == 0 || options.height == 0)) {
117 options.scene->camera->set_full_width(options.width);
118 options.scene->camera->set_full_height(options.height);
119 }
120 else {
121 options.width = options.scene->camera->get_full_width();
122 options.height = options.scene->camera->get_full_height();
123 }
124
125 /* Calculate Viewplane */
126 options.scene->camera->compute_auto_viewplane();
127}
128
129static void session_init()
130{
131 options.output_pass = "combined";
133
134#ifdef WITH_CYCLES_STANDALONE_GUI
136 options.session->set_display_driver(make_unique<OpenGLDisplayDriver>(
138 }
139#endif
140
141 if (!options.output_filepath.empty()) {
142 options.session->set_output_driver(make_unique<OIIOOutputDriver>(
144 }
145
148 }
149#ifdef WITH_CYCLES_STANDALONE_GUI
150 else
152#endif
153
154 /* load scene */
155 scene_init();
156
157 /* add pass for output. */
158 Pass *pass = options.scene->create_node<Pass>();
159 pass->set_name(ustring(options.output_pass.c_str()));
160 pass->set_type(PASS_COMBINED);
161
164}
165
166static void session_exit()
167{
168 if (options.session) {
169 delete options.session;
171 }
172
174 session_print("Finished Rendering.");
175 printf("\n");
176 }
177}
178
179#ifdef WITH_CYCLES_STANDALONE_GUI
180static void display_info(Progress &progress)
181{
182 static double latency = 0.0;
183 static double last = 0;
184 double elapsed = time_dt();
185 string str, interactive;
186
187 latency = (elapsed - last);
188 last = elapsed;
189
190 double total_time, sample_time;
191 string status, substatus;
192
193 progress.get_time(total_time, sample_time);
194 progress.get_status(status, substatus);
195 double progress_val = progress.get_progress();
196
197 if (substatus != "")
198 status += ": " + substatus;
199
200 interactive = options.interactive ? "On" : "Off";
201
203 "%s"
204 " Time: %.2f"
205 " Latency: %.4f"
206 " Progress: %05.2f"
207 " Average: %.4f"
208 " Interactive: %s",
209 status.c_str(),
211 latency,
212 (double)progress_val * 100,
213 sample_time,
214 interactive.c_str());
215
216 window_display_info(str.c_str());
217
218 if (options.show_help)
220}
221
222static void display()
223{
225
226 display_info(options.session->progress);
227}
228
229static void motion(int x, int y, int button)
230{
231 if (options.interactive) {
232 Transform matrix = options.session->scene->camera->get_matrix();
233
234 /* Translate */
235 if (button == 0) {
236 float3 translate = make_float3(x * 0.01f, -(y * 0.01f), 0.0f);
237 matrix = matrix * transform_translate(translate);
238 }
239
240 /* Rotate */
241 else if (button == 2) {
242 float4 r1 = make_float4((float)x * 0.1f, 0.0f, 1.0f, 0.0f);
243 matrix = matrix * transform_rotate(DEG2RADF(r1.x), make_float3(r1.y, r1.z, r1.w));
244
245 float4 r2 = make_float4(y * 0.1f, 1.0f, 0.0f, 0.0f);
246 matrix = matrix * transform_rotate(DEG2RADF(r2.x), make_float3(r2.y, r2.z, r2.w));
247 }
248
249 /* Update and Reset */
250 options.session->scene->camera->set_matrix(matrix);
251 options.session->scene->camera->need_flags_update = true;
252 options.session->scene->camera->need_device_update = true;
253
255 }
256}
257
258static void resize(int width, int height)
259{
260 options.width = width;
261 options.height = height;
262
263 if (options.session) {
264 /* Update camera */
265 options.session->scene->camera->set_full_width(options.width);
266 options.session->scene->camera->set_full_height(options.height);
267 options.session->scene->camera->compute_auto_viewplane();
268 options.session->scene->camera->need_flags_update = true;
269 options.session->scene->camera->need_device_update = true;
270
272 }
273}
274
275static void keyboard(unsigned char key)
276{
277 /* Toggle help */
278 if (key == 'h')
280
281 /* Reset */
282 else if (key == 'r')
284
285 /* Cancel */
286 else if (key == 27) // escape
287 options.session->progress.set_cancel("Canceled");
288
289 /* Pause */
290 else if (key == 'p') {
293 }
294
295 /* Interactive Mode */
296 else if (key == 'i')
298
299 /* Navigation */
300 else if (options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
301 Transform matrix = options.session->scene->camera->get_matrix();
302 float3 translate;
303
304 if (key == 'w')
305 translate = make_float3(0.0f, 0.0f, 0.1f);
306 else if (key == 's')
307 translate = make_float3(0.0f, 0.0f, -0.1f);
308 else if (key == 'a')
309 translate = make_float3(-0.1f, 0.0f, 0.0f);
310 else if (key == 'd')
311 translate = make_float3(0.1f, 0.0f, 0.0f);
312
313 matrix = matrix * transform_translate(translate);
314
315 /* Update and Reset */
316 options.session->scene->camera->set_matrix(matrix);
317 options.session->scene->camera->need_flags_update = true;
318 options.session->scene->camera->need_device_update = true;
319
321 }
322
323 /* Set Max Bounces */
324 else if (options.interactive && (key == '0' || key == '1' || key == '2' || key == '3')) {
325 int bounce;
326 switch (key) {
327 case '0':
328 bounce = 0;
329 break;
330 case '1':
331 bounce = 1;
332 break;
333 case '2':
334 bounce = 2;
335 break;
336 case '3':
337 bounce = 3;
338 break;
339 default:
340 bounce = 0;
341 break;
342 }
343
344 options.session->scene->integrator->set_max_bounce(bounce);
345
347 }
348}
349#endif
350
351static int files_parse(int argc, const char *argv[])
352{
353 if (argc > 0) {
354 options.filepath = argv[0];
355 }
356
357 return 0;
358}
359
360static void options_parse(int argc, const char **argv)
361{
362 options.width = 1024;
363 options.height = 512;
364 options.filepath = "";
366 options.quiet = false;
369
370 /* device names */
371 string device_names = "";
372 string devicename = "CPU";
373 bool list = false;
374
375 /* List devices for which support is compiled in. */
377 foreach (DeviceType type, types) {
378 if (device_names != "") {
379 device_names += ", ";
380 }
381
382 device_names += Device::string_from_type(type);
383 }
384
385 /* shading system */
386 string ssname = "svm";
387
388 /* parse options */
389 ArgParse ap;
390 bool help = false, profile = false, debug = false, version = false;
391 int verbosity = 1;
392
393 ap.options("Usage: cycles [options] file.xml",
394 "%*",
396 "",
397 "--device %s",
398 &devicename,
399 ("Devices to use: " + device_names).c_str(),
400#ifdef WITH_OSL
401 "--shadingsys %s",
402 &ssname,
403 "Shading system to use: svm, osl",
404#endif
405 "--background",
407 "Render in background, without user interface",
408 "--quiet",
409 &options.quiet,
410 "In background mode, don't print progress messages",
411 "--samples %d",
413 "Number of samples to render",
414 "--output %s",
416 "File path to write output image",
417 "--threads %d",
419 "CPU Rendering Threads",
420 "--width %d",
421 &options.width,
422 "Window width in pixel",
423 "--height %d",
425 "Window height in pixel",
426 "--tile-size %d",
428 "Tile size in pixels",
429 "--list-devices",
430 &list,
431 "List information about all available devices",
432 "--profile",
433 &profile,
434 "Enable profile logging",
435#ifdef WITH_CYCLES_LOGGING
436 "--debug",
437 &debug,
438 "Enable debug logging",
439 "--verbose %d",
440 &verbosity,
441 "Set verbosity of the logger",
442#endif
443 "--help",
444 &help,
445 "Print help message",
446 "--version",
447 &version,
448 "Print version number",
449 NULL);
450
451 if (ap.parse(argc, argv) < 0) {
452 fprintf(stderr, "%s\n", ap.geterror().c_str());
453 ap.usage();
454 exit(EXIT_FAILURE);
455 }
456
457 if (debug) {
460 }
461
462 if (list) {
464 printf("Devices:\n");
465
466 foreach (DeviceInfo &info, devices) {
467 printf(" %-10s%s%s\n",
468 Device::string_from_type(info.type).c_str(),
469 info.description.c_str(),
470 (info.display_device) ? " (display)" : "");
471 }
472
473 exit(EXIT_SUCCESS);
474 }
475 else if (version) {
477 exit(EXIT_SUCCESS);
478 }
479 else if (help || options.filepath == "") {
480 ap.usage();
481 exit(EXIT_SUCCESS);
482 }
483
485
486 if (ssname == "osl") {
488 }
489 else if (ssname == "svm") {
491 }
492
493#ifndef WITH_CYCLES_STANDALONE_GUI
495#endif
496
499 }
500
501 /* find matching device */
502 DeviceType device_type = Device::type_from_string(devicename.c_str());
504
505 bool device_available = false;
506 if (!devices.empty()) {
507 options.session_params.device = devices.front();
508 device_available = true;
509 }
510
511 /* handle invalid configurations */
512 if (options.session_params.device.type == DEVICE_NONE || !device_available) {
513 fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
514 exit(EXIT_FAILURE);
515 }
516#ifdef WITH_OSL
517 else if (!(ssname == "osl" || ssname == "svm")) {
518 fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
519 exit(EXIT_FAILURE);
520 }
523 {
524 fprintf(stderr, "OSL shading system only works with CPU device\n");
525 exit(EXIT_FAILURE);
526 }
527#endif
528 else if (options.session_params.samples < 0) {
529 fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
530 exit(EXIT_FAILURE);
531 }
532 else if (options.filepath == "") {
533 fprintf(stderr, "No file path specified\n");
534 exit(EXIT_FAILURE);
535 }
536}
537
539
540using namespace ccl;
541
542int main(int argc, const char **argv)
543{
544 util_logging_init(argv[0]);
545 path_init();
546 options_parse(argc, argv);
547
548#ifdef WITH_CYCLES_STANDALONE_GUI
550#endif
551 session_init();
553 session_exit();
554#ifdef WITH_CYCLES_STANDALONE_GUI
555 }
556 else {
557 string title = "Cycles: " + path_filename(options.filepath);
558
559 /* init/exit are callback so they run while GL is initialized */
560 window_main_loop(title.c_str(),
565 resize,
566 display,
567 keyboard,
568 motion);
569 }
570#endif
571
572 return 0;
573}
#define DEG2RADF(_deg)
int full_width
Definition buffers.h:87
int full_height
Definition buffers.h:88
NODE_DECLARE int width
Definition buffers.h:72
bool display_device
DeviceType type
string description
static vector< DeviceInfo > available_devices(uint device_type_mask=DEVICE_MASK_ALL)
static DeviceType type_from_string(const char *name)
static vector< DeviceType > available_types()
static string string_from_type(DeviceType type)
Definition pass.h:49
void get_status(string &status_, string &substatus_) const
Definition progress.h:305
void set_cancel(const string &cancel_message_)
Definition progress.h:86
void get_time(double &total_time_, double &render_time_) const
Definition progress.h:168
double get_progress() const
Definition progress.h:200
void set_update_callback(function< void()> function)
Definition progress.h:329
ShadingSystem shadingsystem
Definition scene.h:57
DeviceInfo device
void set_pause(bool pause)
void set_display_driver(unique_ptr< DisplayDriver > driver)
Progress progress
void reset(const SessionParams &session_params, const BufferParams &buffer_params)
Scene * scene
void set_output_driver(unique_ptr< OutputDriver > driver)
#define printf
static void session_init()
static void scene_init()
static BufferParams & session_buffer_params()
static void session_print_status()
static void session_exit()
static void options_parse(int argc, const char **argv)
CCL_NAMESPACE_BEGIN struct Options options
static void session_print(const string &str)
static int files_parse(int argc, const char *argv[])
void xml_read_file(Scene *scene, const char *filepath)
#define function_bind
#define CCL_NAMESPACE_END
#define DEVICE_MASK(type)
DeviceType
@ DEVICE_NONE
@ DEVICE_CPU
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define NULL
int len
#define str(s)
@ PASS_COMBINED
CCL_NAMESPACE_BEGIN void util_logging_init(const char *argv0)
Definition log.cpp:30
void util_logging_verbosity_set(int verbosity)
Definition log.cpp:60
void util_logging_start()
Definition log.cpp:47
int main()
VecBase< float, 4 > float4
string path_filename(const string &path)
Definition path.cpp:380
void path_init(const string &path, const string &user_path)
Definition path.cpp:326
@ SHADINGSYSTEM_OSL
@ SHADINGSYSTEM_SVM
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
bool string_endswith(const string_view s, const string_view end)
Definition string.cpp:114
string string_to_lower(const string &s)
Definition string.cpp:190
SceneParams scene_params
SessionParams session_params
Session * session
string output_filepath
Integrator * integrator
Definition scene.h:128
T * create_node(Args &&...args)
Definition scene.h:203
struct Object * camera
CCL_NAMESPACE_BEGIN double time_dt()
Definition time.cpp:36
ccl_device_inline Transform transform_rotate(float angle, float3 axis)
Definition transform.h:264
ccl_device_inline Transform transform_translate(float3 t)
Definition transform.h:244
float max
#define CYCLES_VERSION_STRING
Definition version.h:18
void window_main_loop(const char *title, int width, int height, WindowInitFunc initf, WindowExitFunc exitf, WindowResizeFunc resize, WindowDisplayFunc display, WindowKeyboardFunc keyboard, WindowMotionFunc motion)
Definition window.cpp:264
void window_opengl_context_disable()
Definition window.cpp:258
bool window_opengl_context_enable()
Definition window.cpp:251
void window_display_info(const char *info)
Definition window.cpp:76
void window_redraw()
Definition window.cpp:352
void window_display_help()
Definition window.cpp:97
double total_time