Blender Hack Blog

オープンソースの総合3DCGソフトウェアのBlenderのコード解析や開発を記録していきます。

Fusion Studio 17でCinema EOS c300 Mark IIのフッテージを読み込めるようにする

はじめに

最新版のFusion Studio 17で、DaVinci Resolve Studioのアクティベーションコードで起動できるようになったとのことで、Fusion Studio 17を導入しました。

しかし、Fusion Studio 17は、デフォルトではCinema EOS c300 Mark IIのフッテージが読み込めません。 DaVinci Resolve Studioでは読み込めるのに不思議です。

FFMpegをインストールすればフッテージを読み込めるようになるようなので試してみました。

なお、導入環境はmacOS Big Sur 11.2.3です。

vook.vc

手順

HomebrewでFFMpegをインストールします。 XCodeコマンドラインツールも必要なので、先にインストールしておきます。

% xcode-select --install
% brew install ffmpeg

これで完了です。 Fusion Studioを起動します。

c300 Mark IIのフッテージを読み込みます。 読み込めるようになりました。 Inspector > Format を確認すると、「FFMPEG Assorted formats」と表示されています。

f:id:fixme:20210320091403p:plain
フッテージの読み込みに成功

以前は、Path Mapの設定が必要だったようですが、このバージョンでは自動的に認識されました。

vfxstudy.com

Hello Arnold Python API

はじめに

今回は、Blenderから外れますが、ArnoldのPython APIを扱うメモです。 シンプルな球体をレンダリングし、JPEGで出力する所まで動かします。

コード

こちらの記事にあるコードを使います。

arnoldsupport.com

from arnold import *
 
AiBegin()
AiMsgSetConsoleFlags(AI_LOG_INFO)
AiMsgInfo('Hello World')
AiEnd()

実行

環境変数PYTHONPATHにArnold SDKPython APIのパスをセットしておきます。 それから上記Pythonコードを実行します。 詳細なログが出力され、「Hello World」も出力されました。

% export PYTHONPATH=/Applications/Autodesk/Arnold-6.0.4.1-darwin/python
% python hello_world.py 
dyld: warning, LC_RPATH @executable_path/. in /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/libai.dylib being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)
dyld: warning, LC_RPATH @rpath in /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/./libAdpSDKWrapper-arnold.dylib being ignored in restricted program because it is a relative path
dyld: warning, LC_RPATH @rpath in /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/./libAdpSDKWrapper-arnold.dylib being ignored in restricted program because it is a relative path
dyld: warning, LC_RPATH @rpath in /Users/yoshinori_sano/Library/Application Support/Autodesk/ADPSDK/bin/AdpSDKCore.bundle/Contents/MacOS/AdpSDKCore being ignored in restricted program because it is a relative path
00:00:00    66MB         | log started Tue Mar  9 09:12:33 2021
00:00:00    66MB         | Arnold 6.0.4.1 [e641c6ed] darwin clang-9.0.1 oiio-2.2.1 osl-1.11.6 vdb-4.0.0 clm-1.1.2.132 rlm-12.4.2 2020/09/25 14:42:01
00:00:00    66MB         | running on pc.local, pid=13396
00:00:00    66MB         |  1 x Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz (6 cores, 12 logical) with 32768MB
00:00:00    66MB         |  macOS 10.16.0, Darwin kernel 20.2.0
00:00:00    66MB         |  soft limit for open files raised from 2560 to 10238
00:00:00    66MB         |  
00:00:00    66MB         | loading plugins from /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/../plugins ...
dyld: warning, LC_RPATH @executable_path/. in /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/libai.dylib being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)
00:00:00    66MB         |  cryptomatte.dylib: cryptomatte uses Arnold 6.0.4.1
00:00:00    66MB         |  cryptomatte.dylib: cryptomatte_filter uses Arnold 6.0.4.1
00:00:00    66MB         |  cryptomatte.dylib: cryptomatte_manifest_driver uses Arnold 6.0.4.1
dyld: warning, LC_RPATH @executable_path/. in /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/libai.dylib being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)
00:00:00    68MB         |  usd_proc.dylib: usd uses Arnold 6.0.4.1
dyld: warning, LC_RPATH @executable_path/. in /Applications/Autodesk/Arnold-6.0.4.1-darwin/bin/libai.dylib being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)
00:00:00    68MB         |  alembic_proc.dylib: alembic uses Arnold 6.0.4.1
00:00:00    68MB         | loaded 5 plugins from 3 lib(s) in 0:00.02
        | Hello World
        |  
        | releasing resources
        | Arnold shutdown

BtoA初期のコードから移植し球体をレンダリング

前回書いた記事でBtoAを紹介しました。

blender-hack.hatenablog.com

BtoA初期のコードに球体をレンダリングするコードがあるので、その部分を抽出してレンダリングしてみます。 少し修正して、グリーンの球体になるようにしてみます。

参考にしたコード: https://github.com/lunadigital/btoa/blob/ece49981dfd55b8ae0e2ccb2cb9bbb43f1ffb00b/engine/__init__.py

import arnold

arnold.AiBegin()

sphere = arnold.AiNode("sphere")
arnold.AiNodeSetStr(sphere, "name", "mysphere")
arnold.AiNodeSetVec(sphere, "center", 0, 4, 0)
arnold.AiNodeSetFlt(sphere, "radius", 4)

shader = arnold.AiNode("standard_surface")
arnold.AiNodeSetStr(shader, "name", "redShader")
arnold.AiNodeSetRGB(shader, "base_color", 0.0, 1.00, 0.0) # 修正
arnold.AiNodeSetFlt(shader, "specular", 0.05)

arnold.AiNodeSetPtr(sphere, "shader", shader)

camera = arnold.AiNode("persp_camera")
arnold.AiNodeSetStr(camera, "name", "Camera")
arnold.AiNodeSetVec(camera, "position", 0, 10, 35)
arnold.AiNodeSetVec(camera, "look_at", 0, 3, 0)
arnold.AiNodeSetFlt(camera, "fov", 45)

light = arnold.AiNode("point_light")
arnold.AiNodeSetStr(light, "name", "pointLight")
arnold.AiNodeSetVec(light, "position", 15, 30, 15)
arnold.AiNodeSetFlt(light, "intensity", 4500)
arnold.AiNodeSetFlt(light, "radius", 4)

options = arnold.AiUniverseGetOptions()
arnold.AiNodeSetInt(options, "AA_samples", 8)
arnold.AiNodeSetInt(options, "xres", 1920) # 修正
arnold.AiNodeSetInt(options, "yres", 1080) # 修正
arnold.AiNodeSetInt(options, "GI_diffuse_depth", 4)
arnold.AiNodeSetPtr(options, "camera", camera)

driver = arnold.AiNode("driver_jpeg")
arnold.AiNodeSetStr(driver, "name", "jpegDriver")
arnold.AiNodeSetStr(driver, "filename", "myFirstRender.jpg")

filter = arnold.AiNode("gaussian_filter")
arnold.AiNodeSetStr(filter, "name", "gaussianFilter")

outputs = arnold.AiArrayAllocate(1, 1, arnold.AI_TYPE_STRING)
arnold.AiArraySetStr(outputs, 0, "RGBA RGBA gaussianFilter jpegDriver")
arnold.AiNodeSetArray(options, "outputs", outputs)

arnold.AiRender(arnold.AI_RENDER_MODE_CAMERA)

arnold.AiEnd()

コードを実行すると、以下の球体がレンダリングされました。

f:id:fixme:20210309093427j:plain
Arnold Python APIレンダリングした結果

Blender to Arnold: 開発初期のコード解析から見えてくること

はじめに

Luna Digital社が中心となって、BlenderからArnoldを使えるようにするアドオン(BtoA)を開発中です。 まだアルファ版の段階です。

BtoAの開発が開始された初期の頃のコードを解析した結果、以下が分かりました。

つまり、ArnoldのPython APIをはじめて触れる開発者にとって、理解しやすいコードになっていました。

今回は、BtoAの開発が開始された最初の頃のコードを復元して、そのコードで画像をレンダリングしてみます。 最後に、BtoA開発で必要になる作業とは何なのかも考えてみます。

github.com

BtoAのインストール

BtoAは、現状Blender 2.8系しかサポートされていないようです。 そこで、2.83 LTS版を使用することにします。 githubからコードをcloneして、Blenderからアドオンとして認識できるようにシンボリックリンクを作成します。

% mkdir ~/projects
% cd ~/projects
% git clone https://github.com/lunadigital/btoa.git
% ln -s /Users/yoshinori_sano/projects/btoa /Users/yoshinori_sano/Library/Application\ Support/Blender/2.80/scripts/addons/btoa

Arnold SDKをインストールし、BtoAの設定画面を開いてArnold SDKのパスを指定します。

f:id:fixme:20210307131728p:plain
BtoAの設定

BtoAのコードリーディング

BtoAは、アルファ版でまだコミット数も少ないです。 開発初期のコミットを順番に読んでいくと、いきなり途中段階のコードがgitに追加されたのではなく、少しずつ順番に開発されていることが分かりました。

このコミットで、ArnoldのPython API経由でレンダリングする実験的なコードが追加されました。 github.com

そこで、このコードに遡って、コミットされた当時の状態を再現してみることにします。

% git checkout ece49981dfd55b8ae0e2ccb2cb9bbb43f1ffb00b

Blenderを再起動して、Render Properties > Render Engine > Arnoldに変更します。 そして、Render > Render Image を実行します。 ですが、期待通りに動きませんでした。

コミットログにはホームディレクトリにレンダリング結果が書き込まれるとあるのですが、ローカル環境では権限の関係でうまく書き出されなかったので、/tmp以下に書き込まれるように修正しました。

% git diff
diff --git a/engine/__init__.py b/engine/__init__.py
index aa00af9..9e0ebd3 100644
--- a/engine/__init__.py
+++ b/engine/__init__.py
@@ -58,7 +58,7 @@ class ArnoldRenderEngine(bpy.types.RenderEngine):
 
         driver = arnold.AiNode("driver_jpeg")
         arnold.AiNodeSetStr(driver, "name", "jpegDriver")
-        arnold.AiNodeSetStr(driver, "filename", "myFirstRender.jpg")
+        arnold.AiNodeSetStr(driver, "filename", "/tmp/myFirstRender.jpg")
 
         filter = arnold.AiNode("gaussian_filter")
         arnold.AiNodeSetStr(filter, "name", "gaussianFilter")

もう一度同じ操作をすると、以下のファイルがレンダリングされました。

f:id:fixme:20210307130547j:plain
Arnoldでのレンダリングの結果

コードの詳細

engine/init.py を読んでいきます。 Blenderに新たなレンダリングエンジンを認識させるには、bpy.types.RenderEngineを継承したクラスを実装すれば良いようです。

# For more info, visit:
# https://docs.blender.org/api/current/bpy.types.RenderEngine.html
class ArnoldRenderEngine(bpy.types.RenderEngine):

コードにコメントされている以下のURLには、bpy.types.RenderEngineの継承のやり方の解説が書かれています。 docs.blender.org

Blenderレンダリングを実行すると、このrender()が呼ばれます。 depsgraphから、レンダリング対象の幅と高さを取得します。

その後は、ArnoldのPython APIを使って、Arnoldがレンダリングに必要なモデル情報のジオメトリ、そのジオメトリのマテリアル、カメラ、照明などを構築していきます。 その他、レンダリングに必要な情報をセットした後、arnold.AiRender()レンダリングが実行されます。

class CustomRenderEngine(bpy.types.RenderEngine):
[...]
    def render(self, depsgraph):
        scene = depsgraph.scene
        
        scale = scene.render.resolution_percentage / 100.0
        self.size_x = int(scene.render.resolution_x * scale)
        self.size_y = int(scene.render.resolution_y * scale)

        arnold.AiBegin()

        sphere = arnold.AiNode("sphere")
        arnold.AiNodeSetStr(sphere, "name", "mysphere")
        arnold.AiNodeSetVec(sphere, "center", 0, 4, 0)
        arnold.AiNodeSetFlt(sphere, "radius", 4)

        shader = arnold.AiNode("standard_surface")
        arnold.AiNodeSetStr(shader, "name", "redShader")
        arnold.AiNodeSetRGB(shader, "base_color", 1, 0.02, 0.02)
        arnold.AiNodeSetFlt(shader, "specular", 0.05)

        arnold.AiNodeSetPtr(sphere, "shader", shader)

        camera = arnold.AiNode("persp_camera")
        arnold.AiNodeSetStr(camera, "name", "Camera")
        arnold.AiNodeSetVec(camera, "position", 0, 10, 35)
        arnold.AiNodeSetVec(camera, "look_at", 0, 3, 0)
        arnold.AiNodeSetFlt(camera, "fov", 45)

        light = arnold.AiNode("point_light")
        arnold.AiNodeSetStr(light, "name", "pointLight")
        arnold.AiNodeSetVec(light, "position", 15, 30, 15)
        arnold.AiNodeSetFlt(light, "intensity", 4500)
        arnold.AiNodeSetFlt(light, "radius", 4)

        options = arnold.AiUniverseGetOptions()
        arnold.AiNodeSetInt(options, "AA_samples", 8)
        arnold.AiNodeSetInt(options, "xres", self.size_x)
        arnold.AiNodeSetInt(options, "yres", self.size_y)
        arnold.AiNodeSetInt(options, "GI_diffuse_depth", 4)
        arnold.AiNodeSetPtr(options, "camera", camera)

        driver = arnold.AiNode("driver_jpeg")
        arnold.AiNodeSetStr(driver, "name", "jpegDriver")
        arnold.AiNodeSetStr(driver, "filename", "/tmp/myFirstRender.jpg")

        filter = arnold.AiNode("gaussian_filter")
        arnold.AiNodeSetStr(filter, "name", "gaussianFilter")

        outputs = arnold.AiArrayAllocate(1, 1, arnold.AI_TYPE_STRING)
        arnold.AiArraySetStr(outputs, 0, "RGBA RGBA gaussianFilter jpegDriver")
        arnold.AiNodeSetArray(options, "outputs", outputs)

        arnold.AiRender(arnold.AI_RENDER_MODE_CAMERA)

        arnold.AiEnd()
[...]

結局、BtoA開発で必要になる作業とは何なのか?

Blenderモデリングされたジオメトリ、マテリアル、カメラ、照明などレンダリングに必要な情報を、Arnoldが理解できるデータ構造やAPI呼び出しの形にひたすら整えて行く。 この作業が、BtoA開発の大半で必要な作業になると予想します。

例えば、メッシュのレンダリングは以下で実装されました。ここでも、Blender上にあるシーンのメッシュ情報をArnoldのデータ構造やAPI呼び出しに対応付けています。

github.com

それらに加えて、ユーザーからArnoldの機能をアクセスするための、UIの実装ももちろん必要になると思います。

参考情報

ArnoldをPython APIから使用する際に必要になるリファレンスです。

APIリファレンス

このBlogによると、Arnold SDKC++ APIリファレンスを参照とのことです。APIは基本的に一対一対応しているそうです。

For documentation, you use the Arnold SDK documentation. It’s for the C++ API, but the Python API is basically a one-to-one wrapper around the C++ API.

arnoldsupport.com

docs.arnoldrenderer.com

ノードリファレンス

ArnoldのPython APIでノードを構築していく際、こちらのノードリファレンスが参考になります。

docs.arnoldrenderer.com

例えば、上記のパースペクティブありのカメラ(persp_camera)の仕様は以下にあります。 開発の際は、この仕様書に記載されているパラメータを参照しながら、ノードにセットしていくことになります。

docs.arnoldrenderer.com

Blender: はじめてのビルドエラーの解決

はじめに

最新のコードをビルドしようとすると、エラーが発生してビルドできなくなりました。 今までmasterの最新のコードでうまくビルドできていました。 masterはunstableなので、これからも同様の問題が起きそうです。 解決までの記録を残します。

使用したコード

master (2.93.0)を使用しました。 https://developer.blender.org/rBbcd369c3c12e48dd2be544fbd3ebed2ce8b4c1fb

エラーの内容

ビルドすると、以下のエラーが発生します。 Clangは、ローカルで使用できているので、どうもClangの検出がうまくできていないようです。

% make debug

Configuring Blender in "/Users/yoshinori_sano/blender-git/build_darwin_debug" ...
-- Detected OS X 11.1 and Xcode 12.4 at /Applications/Xcode.app/Contents/Developer
-- SDKs Directory: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform//Developer/SDKs
-- Detected OSX_SYSROOT: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform//Developer/SDKs/MacOSX11.1.sdk
-- Could NOT find sse2neon (missing: SSE2NEON_INCLUDE_DIR) 
-- Could NOT find Clang (missing: _CLANG_LIBRARIES) 
CMake Error at build_files/cmake/platform/platform_apple.cmake:339 (message):
  Clang not found.
Call Stack (most recent call first):
  CMakeLists.txt:916 (include)


-- Configuring incomplete, errors occurred!
See also "/Users/yoshinori_sano/blender-git/build_darwin_debug/CMakeFiles/CMakeOutput.log".
See also "/Users/yoshinori_sano/blender-git/build_darwin_debug/CMakeFiles/CMakeError.log".
make: *** [all] Error 1

一時的な解決

このコミットでClangのチェックコードが追加されていました。 https://developer.blender.org/rB4fb0c83c1c8529b61d38d8a409caf58d05a53bd9

そこで、messageのFATAL_ERRORを踏まないようにコメントアウトすると、ビルドできるようになりました。

diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 31302bf1100..1e0b2db6d81 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -336,7 +336,7 @@ if(WITH_LLVM)
   if(WITH_CLANG)
     find_package(Clang)
     if(NOT CLANG_FOUND)
-       message(FATAL_ERROR "Clang not found.")
+       #message(FATAL_ERROR "Clang not found.")
     endif()
   endif()

問題の探求と解決

Blenderの開発者によって問題はすでに発見、解決されていました。

コミットログによると、外部ライブラリの更新作業が前後したことで、ビルドができなくなったようです。

こちらにも、Clang関係のファイルがSubversionに追加されているのが確認できました。 https://developer.blender.org/rBL62576

commit 9a1b29e16c216c2827f28214d4f7af4ee072beec
Author: Sebastián Barschkis <sebbas@sebbas.org>
Date:   Wed Feb 24 20:18:07 2021 +0100

    CMake: Removed temporarily disabled clang block
    
    Was disabled in rBc778fd981e63. Libraries have been updated in rBL62576.

diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index c2e46206046..31302bf1100 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -333,13 +333,12 @@ if(WITH_LLVM)
   if(NOT LLVM_FOUND)
     message(FATAL_ERROR "LLVM not found.")
   endif()
-# Temporarily removing clang - new libs still need to be committed
-#  if(WITH_CLANG)
-#    find_package(Clang)
-#    if(NOT CLANG_FOUND)
-#       message(FATAL_ERROR "Clang not found.")
-#    endif()
-#  endif()
+  if(WITH_CLANG)
+    find_package(Clang)
+    if(NOT CLANG_FOUND)
+       message(FATAL_ERROR "Clang not found.")
+    endif()
+  endif()
 
 endif()


commit c778fd981e636d99f819806471e2ee83a3cb76c0
Author: Sebastián Barschkis <sebbas@sebbas.org>
Date:   Wed Feb 24 16:12:50 2021 +0100

    CMake: Temporarily removing find clang block
    
    New libs have not landed in the SVN repository. Once they are up, this commit will be reverted.

diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 31302bf1100..c2e46206046 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -333,12 +333,13 @@ if(WITH_LLVM)
   if(NOT LLVM_FOUND)
     message(FATAL_ERROR "LLVM not found.")
   endif()
-  if(WITH_CLANG)
-    find_package(Clang)
-    if(NOT CLANG_FOUND)
-       message(FATAL_ERROR "Clang not found.")
-    endif()
-  endif()
+# Temporarily removing clang - new libs still need to be committed
+#  if(WITH_CLANG)
+#    find_package(Clang)
+#    if(NOT CLANG_FOUND)
+#       message(FATAL_ERROR "Clang not found.")
+#    endif()
+#  endif()
 
 endif()

そこで、外部ライブラリの更新をローカルに取り込んでみます。 Clang関係のファイルが追加されました。 改めて、makeしてみると、無事ビルドエラーが解決しました。

% make update
python3 ./build_files/utils/make_update.py

Updating Precompiled Libraries and Tests

svn --non-interactive cleanup /Users/yoshinori_sano/blender-git/blender/../lib/darwin
svn --non-interactive switch https://svn.blender.org/svnroot/bf-blender/trunk/lib/darwin /Users/yoshinori_sano/blender-git/blender/../lib/darwin
[...]
A    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/clang
A    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/clang/9.0.1
A    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/clang/9.0.1/include
A    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/clang/9.0.1/include/cuda_wrappers
A    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/clang/9.0.1/include/openmp_wrappers
A    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/clang/9.0.1/include/ppc_wrappers
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdShade/resources/generatedSchema.usda
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdSkel/resources/plugInfo.json
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdSkel/resources/generatedSchema.usda
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdShade/resources/usdShade/schema.usda
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdVol/resources/plugInfo.json
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdVol/resources/generatedSchema.usda
U    /Users/yoshinori_sano/blender-git/lib/darwin/usd/lib/usd/usdUI/resources/plugInfo.json
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/bin/llvm-config
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/bin/clang-format
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/include/llvm/Config/llvm-config.h
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMAsmPrinter.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMBitstreamReader.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMCoverage.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMDebugInfoMSF.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMExecutionEngine.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMAnalysis.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMBitReader.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMInstCombine.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMLTO.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMMC.a
U    /Users/yoshinori_sano/blender-git/lib/darwin/llvm/lib/libLLVMMCParser.a
[...]

macOS: Visual Studio CodeでBlenderの開発環境を構築する

はじめに

Blender開発者によるライブコーディングを観ていると、Visual Studio Codeがとても便利そうでした。 そこで、macOSにてVisual Studio Code(以下VSCode)でBlenderの開発環境を構築してみます。

www.youtube.com

手順

こちらのマニュアルを参考にしました。 https://wiki.blender.org/wiki/Developer_Intro/Environment/Portable_CMake_VSCode

VS Codeのインストール

VSCodeを本家からダウンロードしてインストールします。 zipファイルを展開して、アプリケーションにコピーします。

code.visualstudio.com

拡張のインストール

本家のマニュアルに列挙されている拡張をインストールします。

フォーマッタの設定

Code > Preferences > Settingsを開きます。 検索フォームに「format」と入力し、「Editor: Default Formatter」の設定で、「ms-vscode.cpptools 」を選択します。

インテリセンスの設定

本家のマニュアルを読むと少し面倒な工程が必要そうです。 まずは、ビルドとデバッグをできるように整えたいので、ここではこの工程はスキップします。

Blenderのビルド

tasks.jsonに以下を設定し、ビルドを実行します。

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Blender",
            "type": "shell",
            "command": "make",
            "group": "build"
        }
    ]
}

Blenderデバッグ版のビルド

前のステップでBlenderをビルドするとbuild_darwinというディレクトリ以下に様々なファイルが作成されます。 build_darwin/CMakeCache.txtにあるCMAKE_BUILD_TYPEReleaseDebugに変更します。 その後、VSCodeからビルドを実行します。

CMAKE_BUILD_TYPE:STRING=Debug

デバッガの設定

VSCodeからデバッグできるように、launch.jsonを以下のように記述します。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(lldb) Launch Blender",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/../build_darwin/bin/Blender.app/Contents/MacOS/Blender",
            "args": [],               // You could place a .blend file path here to open it by default, or any other Blender args
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false, // This could be set to true if you prefer an external console for debugging
            "MIMode": "lldb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "Build Blender" // Optional; you can use if you want it to build before launching
        }
    ]
}

本家はLinux向けなので注意が必要です。 macOS向けに以下の修正を加えます。

ポイント
  • program: build_darwin以下に生成されるBlenderを指定
  • MIMode: lldbを指定

デバッグの実行

VSCodeで適当な場所にブレークポイントを設定します。 ここでは、Blenderを起動したら必ず実行される、void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)の関数の先頭に設定することにします。

Runから「(lldb) Launch Blender」をクリックしてデバッグを実行します。 launch.jsonのpreLaunchTaskに「Build Blender」を指定したので、Blenderのビルド後、デバッガが起動します。

設定したブレークポイントで実行が停止します。 Xcodeのデバッガと遜色なくデバッグができます。

f:id:fixme:20210224122855p:plain
VSCodeデバッグに成功

実験: ワイヤーフレームの色を変更してみる

はじめに

今回は、Blenderワイヤーフレームの色をHackして変更してみます。 GLSL(OpenGL Shading Language)の知識が役に立ちました。

使用したコード

master (2.93.0)を使用しました。 https://developer.blender.org/rBd447bd3e4a9a793364b5f4951ad280fe0293d79e

ワイヤーフレームが描画される仕組み

頂点シェーダとフラグメントシェーダでモデルのワイヤーフレームが描画されます。 頂点シェーダで定義されているfinalColorワイヤーフレームの色がセットされて、フラグメントシェーダでfinalColorを参照して最終的な色(fragColor)にセットされます。

source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl

out vec4 finalColor;
[...]
void main()
{
[...]
  vec3 rim_col, wire_col;
  if (isObjectColor || isRandomColor) {
    wire_object_color_get(rim_col, wire_col);
  }
  else {
    wire_color_get(rim_col, wire_col);
  }

  facing = clamp(abs(facing), 0.0, 1.0);

  /* Do interpolation in a non-linear space to have a better visual result. */
  rim_col = pow(rim_col, vec3(1.0 / 2.2));
  wire_col = pow(wire_col, vec3(1.0 / 2.2));
  vec3 final_front_col = mix(rim_col, wire_col, 0.35);
  finalColor.rgb = mix(rim_col, final_front_col, facing);
  finalColor.rgb = pow(finalColor.rgb, vec3(2.2));
  finalColor.a = wireOpacity;
  finalColor.rgb *= wireOpacity;
}

source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl

in vec4 finalColor;
[...]
void main()
{
[...]
  fragColor = finalColor;

ちなみに、wireframe_vert.glslwireframe_frag.glslはビルド時に、const char[]型のdatatoc_wireframe_vert_glsldatatoc_wireframe_frag_glslにそれぞれ変換されるようです。 そして、OVERLAY_shader_wireframe()でシェーダープログラムとしてロードされます。

source/blender/draw/engines/overlay/overlay_shader.c

GPUShader *OVERLAY_shader_wireframe(bool custom_bias)
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
  OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
  if (!sh_data->wireframe[custom_bias]) {
    sh_data->wireframe[custom_bias] = GPU_shader_create_from_arrays({
        .vert = (const char *[]){sh_cfg->lib,
                                 datatoc_common_view_lib_glsl,
                                 datatoc_common_globals_lib_glsl,
                                 datatoc_gpu_shader_common_obinfos_lib_glsl,
                                 datatoc_wireframe_vert_glsl,
                                 NULL},
        .frag = (const char *[]){datatoc_common_view_lib_glsl,
                                 datatoc_common_globals_lib_glsl,
                                 datatoc_wireframe_frag_glsl,
                                 NULL},
        .defs = (const char *[]){sh_cfg->def,
                                 custom_bias ? "#define CUSTOM_DEPTH_BIAS\n" : NULL,
                                 NULL},
    });
  }
  return sh_data->wireframe[custom_bias];
}

ワイヤーフレームの色をセットしている場所の特定

wire_color_get()を見ると、colorWireという変数が見つかりました。この変数にワイヤーフレームの色がセットされていそうです。

void wire_color_get(out vec3 rim_col, out vec3 wire_col)
{
[...]
  else if (is_selected && useColoring) {
    if (isTransform) {
      rim_col = colorTransform.rgb;
    }
    else if (is_active) {
      rim_col = colorActive.rgb;
    }
    else {
      rim_col = colorSelect.rgb;
    }
    wire_col = colorWire.rgb;
  }
  else {
    rim_col = colorWire.rgb;
    wire_col = colorBackground.rgb;
  }
}

colorWiregrepしてみると、以下のuniform変数として定義されていることが分かりました。

source/blender/draw/intern/shaders/common_globals_lib.glsl

/* keep in sync with GlobalsUboStorage */
layout(std140) uniform globalsBlock
{
  vec4 colorWire;
  vec4 colorWireEdit;
  vec4 colorActive;
  vec4 colorSelect;
[...]

もう少し探索を進めると、uniform変数にセットしていそうなコードが見つかりました。 UI_GetThemeColor4fv(TH_WIRE, gb->colorWire);にbreak pointをセットしてみます。 デバッガで確認すると、初回実行時には、ゼロ初期化されていて、DRW_globals_update(void)の呼び出し後は、 gb->colorWireに(0, 0, 0, 1)がセットされました。

source/blender/draw/intern/draw_common.c

void DRW_globals_update(void)
{
  GlobalsUboStorage *gb = &G_draw.block;

  UI_GetThemeColor4fv(TH_WIRE, gb->colorWire);
  UI_GetThemeColor4fv(TH_WIRE_EDIT, gb->colorWireEdit);
  UI_GetThemeColor4fv(TH_ACTIVE, gb->colorActive);
  UI_GetThemeColor4fv(TH_SELECT, gb->colorSelect);
[...]

コードの修正

colorWireは、float[4]でそれぞれの要素はRGBAに対応しているようです。 そこで、rgba = (1, 0, 0, 1)、つまり赤をセットしてみます。

diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 132b5274517..db7501e6a94 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -53,7 +53,12 @@ void DRW_globals_update(void)
 {
   GlobalsUboStorage *gb = &G_draw.block;
 
-  UI_GetThemeColor4fv(TH_WIRE, gb->colorWire);
+  gb->colorWire[0] = 1.0;
+  gb->colorWire[1] = 0.0;
+  gb->colorWire[2] = 0.0;
+  gb->colorWire[3] = 1.0;
+
+  //UI_GetThemeColor4fv(TH_WIRE, gb->colorWire);
   UI_GetThemeColor4fv(TH_WIRE_EDIT, gb->colorWireEdit);
   UI_GetThemeColor4fv(TH_ACTIVE, gb->colorActive);
   UI_GetThemeColor4fv(TH_SELECT, gb->colorSelect);

ビルドと実行結果

ビルドして実行し、ワイヤーフレームで表示すると無事ワイヤーフレームの色が赤くなりました。

f:id:fixme:20210223110934p:plain
ワイヤーフレームの色が変更された

関連情報

ワイヤーフレームの不透明度をUIから変更できるようにする修正

⚙ D7622 Add An Opacity Slider to Overlay Wireframe

Blenderのはじめての不具合改修

はじめに

BlenderXcodeデバッグ実行した時にNull Pointer Exceptionが発生する不具合を発見しました。 軽微な不具合だったので、改修してパッチを送りました。その過程を簡単にメモに残しておきます。

使用したコード

master (af940c68cbed7e840d6ae58f2645ff12ed6abffb) 2.93.0を使用しました。

バグの詳細

環境変数BLENDER_SYSTEM_PYTHONを未設定の状態でBlenderを実行すると、Null Pointer Exceptionが発生します。 こちらに詳細をまとめて、パッチを送りました。 https://developer.blender.org/D10494

git loggit blameでバグが混入したコミットを特定しました。

パッチの作成

このページに書かれている、Arcanistをインストールしました。 https://wiki.blender.org/wiki/Tools/CodeReview

はじめて使用する際には、以下のコマンドを実行して、パッチの送付先のシステム認証を行う必要があります。

% arc install-certificate

以下のコマンドを実行するとコードのコミットとチケットの作成が行われます。

% arc diff

コミッターにレビューを依頼しました。

無事、修正が取り込まれました。 https://developer.blender.org/rB06212759bc7285a131c3ee811aec1ee240841c2c

commit 06212759bc7285a131c3ee811aec1ee240841c2c
Author: Campbell Barton <ideasman42@gmail.com>
Date:   Mon Feb 22 21:20:48 2021 +1100

    Fix missing NULL check on macOS when system-python isn't found
    
    Regression from cafd6b519c5f5c4b67d0dfe3d453cd4223b38716.
    
    D10494 by @ysano with edits.