mitsuba-blender icon indicating copy to clipboard operation
mitsuba-blender copied to clipboard

Export from command line

Open G-nn-r opened this issue 2 years ago • 4 comments

Hi,

it would be really nice to be able to do exports directly from the command line. Like that, the add-on will become more versatile and can even be executed without a GUI (when using blender -b, see here)). That is especially helpful for GUI-less Blender operation, e.g., when working on a specific machine via SSH.

Personally, I would say that a Python script, which handles this and possibly allows options via a CLI, would be the easiest and best option. (I.e., usage would somehow look like this: blender somescene.blend -b --python new_exporter_script.py and could be wrapped further with a shell script.)

Thank you!

G-nn-r avatar May 02 '22 07:05 G-nn-r

Hi,

This is already supported, as all blender operators are registered in the Blender Python API. In general, you can find the API handle of each operator/parameter in the Blender UI by enabling "Python tooltips" in the Blender preferences (Interface > Display). Hovering over any operator/parameter will then show you the associated handle in the API.

In the case of this addon, the operator to call to export from the blender API should be bpy.ops.export_scene.mitsuba2

The full signature is as follows: bpy.ops.export_scene.mitsuba2(filepath="", check_existing=True, filter_glob="*.xml", use_selection=False, split_files=False, export_ids=False, ignore_background=True, axis_forward='-Z', axis_up='Y')

You can get those signatures in the Python interactive console inside of blender, by just entering the name of the operator.

Please let me know if this doesn't work for you.

bathal1 avatar May 02 '22 08:05 bathal1

Thanks for the quick reply!

I already tried a little bit to go in that direction, but then ran into issues (I think I got the filepath argument wrong)...

With your suggested signature, I was able to export scenes. But, on Windows, is very crucial to state your path with double backslashes (bpy.ops.export_scene.mitsuba2(filepath="D:\\myfolder\\mysubfolder\\myfile.xml", check_existing=True, [...])) instead of a single forward slash ("D:/myfolder/mysubfolder/myfile.xml"). If you work with single forward slashes, the first few parts of the XML (i.e., the Defaults, Camera and Rendering Parameters, Materials, and Emitters sections) are created successfully, the it fails in the creation of the Shapes-block. It took me quite a while to figure out that the double backslashes fix this, because the error is so strange. I know why I usually use the pathlibmodule on Windows 😄

In case anyone runs into a similar problem, here is my traceback:

PS C:\> blender "D:/scenes/myscene/myscene.blend" -b --python-console
Blender 2.82 (sub 7) (hash 375c7dc4caf4 built 2020-03-12 15:41:08)
Read prefs: C:\Users\myuser\AppData\Roaming\Blender Foundation\Blender\2.82\config\userpref.blend
found bundled python: C:\Program Files\Blender Foundation\Blender 2.82\2.82\python
Read blend: D:/scenes/myscene/myscene.blend
Python 3.7.4 (default, Nov  1 2019, 13:23:36) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
>>> import bpy
>>> bpy.ops.export_scene.mitsuba2(filepath="D:/temp/from_commandline/myscene.xml", check_existing=True, use_selection=False, split_files=False, export_ids=False, ignore_background=True, axis_forward='-Z', axis_up='Y')
2022-05-02 11:05:00 INFO  main  [file_api.py:127] log(): Ignoring Blender's default background...
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\blender.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\diffuse.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\uniform.dll" ..
2022-05-02 11:05:00 WARN  main  [BlenderMesh] Mesh Plane-Matte has no texture coordinates!
2022-05-02 11:05:00 INFO  main  [BlenderMesh] Plane-Matte: Removed 2 duplicates
2022-05-02 11:05:00 INFO  main  [Mesh] Writing mesh to "D:/temp/from_commandline\meshes\Plane-Matte.ply" ..
2022-05-02 11:05:00 INFO  main  [Mesh] "D:/temp/from_commandline\meshes\Plane-Matte.ply": wrote 2 faces, 4 vertices (120 B in 0ms)
2022-05-02 11:05:00 WARN  main  [file_api.py:127] log(): Light 'Point' has a non-zero soft shadow radius. It will be ignored.
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\path.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\ply.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\perspective.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\point.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\independent.dll" ..
2022-05-02 11:05:00 INFO  main  [PluginManager] Loading plugin "plugins\hdrfilm.dll" ..
Error: Traceback (most recent call last):
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\export.py", line 154, in execute
    self.export_ctx.write()
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\file_api.py", line 104, in write
    self.xml_writer.process(self.scene_data)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 637, in process
    self.write_dict(self.scene_data[Files.MAIN])
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 574, in write_dict
    self.write_dict(value)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 588, in write_dict
    value = self.format_path(value, self.current_tag())
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 525, in format_path
    copy2(filepath, target_path)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 266, in copy2
    copyfile(src, dst, follow_symlinks=follow_symlinks)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 104, in copyfile
    raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
shutil.SameFileError: 'D:\\temp\\from_commandline\\meshes\\Plane.ply' and 'D:/temp/from_commandline\\meshes\\Plane.ply' are the same file

location: C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\modules\bpy\ops.py:201

Traceback (most recent call last):
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\export.py", line 154, in execute
    self.export_ctx.write()
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\file_api.py", line 104, in write
    self.xml_writer.process(self.scene_data)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 637, in process
    self.write_dict(self.scene_data[Files.MAIN])
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 574, in write_dict
    self.write_dict(value)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 588, in write_dict
    value = self.format_path(value, self.current_tag())
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 525, in format_path
    copy2(filepath, target_path)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 266, in copy2
    copyfile(src, dst, follow_symlinks=follow_symlinks)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 104, in copyfile
    raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
shutil.SameFileError: 'D:\\temp\\from_commandline\\meshes\\Plane.ply' and 'D:/temp/from_commandline\\meshes\\Plane.ply' are the same file

location: C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\modules\bpy\ops.py:201

location: C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\modules\bpy\ops.py:201
Error: Traceback (most recent call last):
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\export.py", line 154, in execute
    self.export_ctx.write()
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\file_api.py", line 104, in write
    self.xml_writer.process(self.scene_data)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 637, in process
    self.write_dict(self.scene_data[Files.MAIN])
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 574, in write_dict
    self.write_dict(value)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 588, in write_dict
    value = self.format_path(value, self.current_tag())
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 525, in format_path
    copy2(filepath, target_path)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 266, in copy2
    copyfile(src, dst, follow_symlinks=folloTraceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\modules\bpy\ops.py", line 201, in __call__
    ret = op_call(self.idname_py(), None, kw)
RuntimeError: Error: Traceback (most recent call last):
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\export.py", line 154, in execute
    self.export_ctx.write()
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\addons\mitsuba2-blender\file_api.py", line 104, in write
    self.xml_writer.process(self.scene_data)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 637, in process
    self.write_dict(self.scene_data[Files.MAIN])
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 574, in write_dict
    self.write_dict(value)
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 588, in write_dict
    value = self.format_path(value, self.current_tag())
  File "D:\mitsuba2\dist\python\mitsuba\python\xml.py", line 525, in format_path
    copy2(filepath, target_path)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 266, in copy2
    copyfile(src, dst, follow_symlinks=follow_symlinks)
  File "C:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\shutil.py", line 104, in copyfile
    raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
shutil.SameFileError: 'D:\\temp\\from_commandline\\meshes\\Plane.ply' and 'D:/temp/from_commandline\\meshes\\Plane.ply' are the same file

location: C:\Program Files\Blender Foundation\Blender 2.82\2.82\scripts\modules\bpy\ops.py:201


... truncated>>>

That brings me to two smaller issues:

  1. The path needs to be set without the GUI. In the readme, it tells that

Point Path to Mitsuba 2's build directory. If the environment variable MITSUBA_DIR was set (cf. Mitsuba 2 install instructions), this field will automatically be filled with the path it contains.

I wasn't able to find the certain section. Just creating a new environment variable didn't seem to solve this.

  1. Maybe, there should be a small section in the readme on how the add-on can be executed from the command line. If you don't want to dig into this right now, I could also write a few sentences about this and create a PR for the updated readme.

G-nn-r avatar May 02 '22 10:05 G-nn-r

Update to point 1: I dug into it and found the problem. The created environment variable (just named mitsuba_dir with mitsuba's build path) is read by the export.py-script. However, there are two processing issues under Windows:

  • The first issue is caused by this line: for token in tokens.split(':'): (see here) On Linux, where different entries of an environment variable are separated by colons (:), everything works fine. But on Windows, environment variables are separated by semicolons (;). So a path D:\mitsuba is splitted into the two parts D: and \mitsuba. Here needs to be distinguished between systems to get the correct seperator.
  • The second issue is caused by the default way of installation of Mitsuba2 on Windows, where the build directory and the mitsuba2 root directory are the same (caused by cmake -G "Visual Studio 16 2019" -A x64, see here). Therefore, the line path = os.path.join(token, 'build') (see here) is unnecessary. path should just be token.

Edit / Update:

I tested it on Linux, there it's working. My test-export script looks like this:

import bpy
bpy.ops.preferences.addon_enable(module="mitsuba2-blender")  # enable the add-on
# bpy.ops.wm.open_mainfile(filepath="/home/scenes/myscene/myscene.blend")  # read a scene if no scene has been specified when starting calling "blender -b --python myscript.py"
bpy.ops.export_scene.mitsuba2(filepath="/home/scenes/myscene/myscene.xml", check_existing=True, use_selection=False, split_files=False, export_ids=False, ignore_background=True, axis_forward='-Z', axis_up='Y')

The filter_glob keyword has to be left out in order for this to work.

Therefore, two issues remain in this ticket:

  1. The exporting does not work from the command line on Windows (see above). I don't really understand why it's working when operating from the GUI... I was only testing on Windows, I have no need to operate from command line on Windows personally.
  2. A short section in the readme on command-line operation would be helpful.

G-nn-r avatar May 04 '22 13:05 G-nn-r

Thanks for looking into this.

The code to use the environment variable ion Windows seems broken indeed, and support for it will likely be dropped in the next release. I recommend you instead set the path manually in your script by accessing directly the preferences of the addon:

C.preferences.addons['mitsuba2-blender'].preferences.mitsuba_path

bathal1 avatar May 09 '22 08:05 bathal1