PythonのVTKでオフスクリーンレンダリングをリモートで利用する

Windows 7からUbuntuのサーバにSSHログインしてpython-vtkのプログラムを走らせようとするとDISPLAYがらみで動かない. vtkRenderWindowにはSetOffScreenRenderingというオプションがあるのだが, これを指定しても結局ハードウェアを動かそうとするらしい. 前から気になっていたのでソフトウェアレンダリングできるようにソースコードからビルドしてみた. ちなみにUbuntuは13.04.

Mesaを用いないものはapt-getでインストールしているので併用することを前提とした(ここでビルドしたものですべて済むわけではない). 下記の内容を参考にした.

http://www.justinribeiro.com/chronicle/2012/11/09/remotely-rendering-high-resolution-models-with-vtk-mesa-3d-cmake-and-three-js/

基本的にはMesaと呼ばれるライブラリを利用するように切り替えれば良い. Mesa自体もビルドできるはずだが, ライブラリのバージョンの問題でうまくいかなかったのでとりあえずそちらはsudo apt-get install libosmesa6-dev libgl1-mesa-devでお茶を濁す.

KitwareのVTKのResources/Downloadから5.10.1のソースコードをダウンロードして展開しておく. ここで初め6.1.0を用いたが後で確認に用いるサンプルコードが5系列にしか対応していない.

$ wget http://www.vtk.org/files/release/5.10/vtk-5.10.1.zip
$ unzip vtk-5.10.1.zip
$ ls
VTK5.10.1
$ mkdir VTK_Build
$ cd VTK_Build

ここからコンパイルしていく. VTKはCMakeなので, 以下のようなオプションをつける.

$ cmake -D"VTK_OPENGL_HAS_OSMESA:BOOL=ON" -D"VTK_USE_OFFSCREEN:BOOL=ON" -D"VTK_USE_X:BOOL=OFF" -D"VTK_WRAP_PYTHON:BOOL=ON" -D"BUILD_SHARED_LIBS:BOOL=ON" ../VTK5.10.1
$ make -j5

これは結構時間かかる. 気長に待つ. これでビルドが成功したら後はサンプルを試す.

http://www.vtk.org/Wiki/VTK/Examples/Cxx/Utilities/OffScreenRendering
http://gitorious.org/vtkwikiexamplestarballs/vtkwikiexamplestarballs/raw/master:OffScreenRendering.tar

$ cd ..
$ wget http://gitorious.org/vtkwikiexamplestarballs/vtkwikiexamplestarballs/raw/master:OffScreenRendering.tar
$ mv master:OffScreenRendering.tar OffScreenRendering.tar
$ tar xvf OffScreenRendering.tar
$ cd OffScreenRendering/build
$ cmake -DVTK_DIR:PATH=/path/to/VTK_Build ..
$ make
$ ./OffScreenRendering

これでscreenshot.pngが出来ていて粗い球みたいなものが描画できていたらC++はOK. 次はPython.

$ LD_LIBRARY_PATH=/path/to/VTK_Build/bin PYTHONPATH=/path/to/VTK_Build/Wrapping/Python:/path/to/VTK_Build/bin python sample.py

Pythonの場合は先に記した通り, renWin.SetOffScreenRendering(True)としておけば良い. 一応僕がどこかからか拾ってきて試したサンプルを下に書いておく.

import vtk

ren = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.SetOffScreenRendering(True)
renWin.AddRenderer(ren)

source = vtk.vtkSphereSource()
source.SetCenter(0, 0, 0)
source.SetRadius(5.0)

mapper = vtk.vtkPolyDataMapper()
mapper.SetInput(source.GetOutput())
actor = vtk.vtkActor()
actor.SetMapper(mapper)

ren.AddActor(actor)
renWin.Render()

w2if = vtk.vtkWindowToImageFilter()
w2if.SetInput(renWin)
w2if.Update()
writer = vtk.vtkPNGWriter()
writer.SetFileName("screenshot.png")
writer.SetInput(w2if.GetOutput())
writer.Write()