Blenderクイズ:SubdivisionSurfeceの結果がおかしい

(今回、持って回った英文翻訳風にざっくり雑にブログ記事を書きたい気持ちだったのでクイズの形式を取っているだけです。答えバレ防止反転表示などはしていないので、本当にクイズ当てしようとせず、軽い気持ちで読んでください。)

 

3Dモデリングソフトウェアは立体という我々が日常に何時も触れている身近な存在を扱うソフトウェアですが、あくまでコンピュータの中にあるObjectは計算で仮想しているものでしかなく、そのため時に思いがけない結果形状を示し、望みの外観を得るためには(私がそういった深い認知を持っているかは棚に上げますが)Blenderへの深い理解や長い経験が必要な場合があります。

 

今回はクイズです。Blender上でSubdivisionSurfece モディファイアを掛けた結果がおかしいのですが、まずどこがおかしいか気づきますでしょうか。そして、原因と解決法は?

 

詳しい状況として、肩掛けのフリルを作成しています。先程Split>Selectionでオブジェクトを分割してフリルを切断し、空いてしまった面を埋めたあと、EditModeでいくらか点を動かして形状の調整をしたところでした。

 こうすると見える対象Objectのフリルの端はObject形状の調整前というだけで、クイズの答えではありません。


正解はフリルのこの面です。


この面だけおかしなことに、SubdivisionSurfeceが効いていません。隣の面と比べれば一目瞭然です。


Blenderでのモデリング中、SubdivisionSurfeceがおかしな結果を示すことは枚挙に暇がありません。

大抵の場合、点の重なりを散々調べることになり、膨大な点を1つずつクリックしてみる作業に1時間を費やした後、面のNormalがおかしいことに気づきFlipで解決、といったコトになります。ですが今回、スクリーンショットをご覧いただければ、最初からFace Orientation のView設定が有効な状態で、一発で見て判るとおり、今回は面のNormalも原因ではないようです。

 

今回、原因を探るには、 別のView設定で見る必要があります。

 

X-Ray設定です。いわゆる透過。

今回のフリルは一見複雑に見えますが、わりと点数が少なく単純な構造です。BlenderとSubdivisionSurfeceの組み合わせのメリットといえます。

閑話休題。

どこがおかしいかわかりましたか?

では原因を発表しましょう。

 


 

今回、スクリーンショットが最初からEditModeのSelectModeがFace selectだったのは重要なヒントだったかもしれません。 

実際にはこの問題を解決した後、記事を書くために、Ctrl+Zだけで問題再現してSelectMode等は切り替えせずスクリーンショットを取ったというだけです。

 

====

これは自慢になってしまうかもしれませんが、私が異常に気づいたのは、フリルの谷の端の分割がおかしくなっているところでした。フリルの谷にも折れ目が発生していますね。

(ちなみにこの前後のスクリーンショットは問題の再現が不完全なので、実際の問題をきちんと再現したスクリーンショットと微妙に形状が違います)
  



====

 Blenderは、そしてモデル奥が深いですね。

残念ながら、今回のそれは実装に必要でなく邪魔するものでしたが。

TIGORA(ティゴラ)のトレッキング シューズ

 TIGORA(ティゴラ)の トレッキング シューズを買いました。


メインの靴がアシックスウォーキングで街歩き用なのですが、これまではこれで高尾山などの軽い山も登っていました。

今回、靴底があまりに摩耗したこともあってアシックスウォーキングを買い替えたのですが、ついでに消耗が激しそうな山歩き用は別の靴を用意して履いてみよう、という感じです。


私が調べたときはamazonで「ティゴラのトレッキングシューズ」とすると背が高いトレッキングシューズしか出てきませんでしたが、ある程度街歩きもできる普通サイズのトレッキングシューズも出ています。


裏側はこんな感じです。





 

靴底の中敷きにも厚みがあり、期待できそうです。

アシックスウォーキング(フィールドウォーカー)を買い替え(新旧比較写真など)

靴を買い替えました。


 

それまでは靴は適当に入った店で最安のスニーカを買っていたのですが、4年ほど前に「足に合う靴」を求めて一念発起し、アシックスウォーキングを買ったのが初めて真剣に靴選びをしました。

そのときはアシックス直営店で足のサイズを測り、中敷きも調整オプションを入れてもらっています。

その後、2年ほどで履き潰したアシックスウォーキングを同じ型番で買い直し、 それもまた2年ほどで履きつぶしたため、同じものを探して買い換えたものです。

現在はフィールドウォーカーという名前になっており、後で見ていくように細部のデザインも違うため、厳密には違う靴なのかもしれません。

(あまり関心がないためこういう認識になってます。)

 最初の選定時に見た目はあまり気にしていなかったのですが、革というかフェルト革風のデザインも靴としては珍しく、今では気に入っております。

 

 というわけで上から撮った写真。

中敷きは真っ赤です。とはいえ靴紐のように外からは見えないので悪目立ちのようなことはしません。

 


購入時ではなくちょっと履いたあとですが、足裏はこんな感じです

 

内側の写真。比較写真はないですが比べてみると、靴のべろが被覆でくっついているように変わっています。


 後ろ側もデザインが違います

後部を横から見ると、紐の衣装があったのが省略されています


側面としてはメッシュ風のラインが入る感じに変更されています。



 
 
並べてみると古い方の履きつぶしっぷりが解ると思います。
次は少なくとも踵にもうちょっと気を遣うようにしたいです。




横から見た感じ。外見の靴底の厚みなどは変わらないように見えます。


WebExtensionsのAPIの非同期対応が呼び出し箇所により異なる(Async,Primise)

 TL;DR

FireFoxでchrome.*()系APIを使うとき、content_scriptだけpromiseなAPIで、ほかはコールバックな模様


概要

そもそも、
- FireFoxはChrome拡張機能互換の一環として、chrome.storage.local.get()といったchrome.*()系APIを実装している
https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/get
> この API は Chromium の chrome.storage API に基づいています。
- MDNのドキュメントではchrome.*()系APIはコールバックで非同期を返すものとなっている
(前述のURLにて。2024年現在も)
- Chromeブラウザのchrome.*()系APIは実際にコールバックのAPIで、Primise非対応だった
(おそらく当初、あるいはmanifest V2の頃は)
- 2023年時点のFireFoxでは、chrome.*()系APIはPrimise非対応だった
(当時の挙動からおそらくそう思われる)

- 一方、現在のChromeはchrome.storage.local.get()はPromiseを返すようになっている
(2024年現在。ドキュメントに記載されている通りならば)
https://developer.chrome.com/docs/extensions/reference/api/storage?hl=ja
> chrome.storage.local.get(["key"]).then((result) => {

- 2024年、FireFoxのchrome.*()系APIは、content_script内ではpromiseを返すようになった模様
(とりあえずchrome.storage.local.get()は。全てのAPIが対応しているかは不明。)


説明


気づいたのはdaisy AddCharaIconブラウザ拡張の開発中で、これはページ内のゲーム登場人物名の横に顔アイコンを付与するブラウザ拡張。
毎回アイコン画像をloadするのは負荷が高いため、ローカルでキャッシュするためにWebExtensionsのstorage APIを叩いていて気づいた。




https://github.com/MichinariNukazawa/add_chara_icon_webextensions


```: option_page/option_page.js

const getHashFromTitle = async (title) => {
return new Promise((resolve) => {
// TODO FireFoxではchrome.storage.local.*()で
//promise構文が通用しない様子
// (FireFox127.0.2, 2024/07, Ubuntu 24.04)
chrome.storage.local.get(null, (hash) => {
//console.log('src', hash);
const filterHashFromTitle = (title, hash) => {
let res = {};
for(let key in hash){
if(hash[key].title == title){
res[key] = hash[key];
}
}
return res;
}
const res = filterHashFromTitle(title, hash);
resolve(res);
});
});
};

```


面白いのはoption_pageでもPromise()構文自体は有効であることで、これはcallback版をPromiseでwrapして機能していることからわかる。
つまりFireFoxではchrome.storage.local.get() API側が2種類あるということで、content_scriptとそれ以外で同じAPIのインタフェースが異なる、ということを示しているのだと考えられる。

Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換する

 Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換することができるが、上手く変換されない場合がある。

 

以前作った魔法陣イラスト素材をイラスト素材ストックサイトへ登録しようと思い立ち、改めて素材用にラスタライズ変換をかけようとした。

 

ラスタライズ変換にはImageMagickの convert が使用でき、DPI的な設定  -density 600  でサイズ調整している。


` convert -density 600 $filename.svg $filename-ss.jpg `

 

元画像はこちら


 変換結果はこのようになってしまう。

30枚の画像をSVGからJPGへ変換した結果、6枚ほど結果が明らかにおかしい。
 

失敗しているものを拡大した抜粋。


真っ白で明らかに変換できていないものもあれば、circle要素などSVG画像から一部が抜け落ちてしまっているものもある。

 

また上のような真っ白な変換失敗や大きなパーツの欠損は明らかに見てわかるのでまだ良いが、小さなパーツの漏れ欠けがあるかもしれないし、そうなると今回のように多数の画像を扱っている中では見落としが起こると思う。

 

コマンドラインでバッチ処理したのだが、いくつかはエラーが通知されている。

```

MN@daisy-bell:MagickCircle/$ bash a.sh
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.

```

ただ、 ` memory allocation failed` とはいうものの、メモリはかなりとっているのだが。

```  /etc/ImageMagick-6/policy.xml

<policy domain="resource" name="memory" value="8GiB"/>
<policy domain="resource" name="map" value="8GiB"/>
<policy domain="resource" name="width" value="128KP"/>
<policy domain="resource" name="height" value="128KP"/>
<policy domain="resource" name="area" value="2048MP"/>
<policy domain="resource" name="disk" value="16GiB"/>

```

 

小さなサイズで出力してみる。

```

convert -density 600 $filename.svg $filename-ss.jpg

convert -density 90 $filename.svg $filename-3ss.jpg

 ```

 

 

小さなサイズで出力すると、たしかに結果が改善する。


 エラー通知も1個減っていた。

 


とはいえ、ストックサイトへ登録するにあたっては大きいサイズでほしいのだが。

 

GIMPでもSVGをインポートしてラスタライズすることができる。

GUI操作で読み込むと任意のスケールで問題なく読み込めるのだが、CLI呼び出しでバッチ処理に使おうとすると、きちんと変換された結果が出ない。


 画像のような変換結果になる。変換されているごく一部のパーツを見るだけでも、明らかに画質が悪い。

またこの場合は背景を 白背景で書き出せば上手く行きそうに見えるが、試した範囲では、変換結果が真っ白になるだけで上手く行かなかった。

 

以下、うまく行かなかったGIMPでのSVGインポート変換を一応抜粋。

```

# GIMPのコマンドを使ってSVGを読み込む
gimp -i -b - <<EOF
(let* (
       (image (car (gimp-file-load RUN-NONINTERACTIVE "$input_file" "$input_file")))
       (drawable (car (gimp-image-get-active-layer image)))
       (new-width $size)
       (new-height $size)
       )
  (gimp-image-scale image new-width new-height)
  (file-jpeg-save RUN-NONINTERACTIVE image drawable "$output_file" "$output_file" 0.9 0 1 0 "" 0 1 0 1)
  (gimp-image-delete image)
  )
(gimp-quit 0)
EOF

```


またGIMP操作にはもう1つ、Pythonからgimpfuを経由して呼び出す方法もあり、こちらは上野LISPな古いGIMPスクリプトより高度な操作ができるのだが、現状GIMPがPython3に対応していないとかで、今回は断念した。

FireFoxでcontent_scripts内のconsole.log()のメッセージが出力されない

 本件は、2023/09頃には解決しているはずの話です。

 

TL;DR 

Q. chromeで動いたwebextensionsがFireFoxでcontent_scripts内のconsole.log()のメッセージをコンソールに出力しないのはなぜか?

A. FireFoxが 2023/06 FireFox 114.0時点でmanifest v3に対応していないにもかかわらずエラーを全く出さないため。

 

# 再現

 

```: ディレクトリ構成

DaisyWarekiConv/

├── manifest.json

├── icons/icon128.png

└── my_content_script.js

 ```

```: my_content_script.js

console.log("hello webextensions daisy wareki conv.");

```

```: manifest.json

{
"manifest_version": 3,
"name": "dev-DaisyWarekiConv",
"version": "0.0.1",

"icons": {
"128": "icons/icon128.png"
},

"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["my_content_script.js"]
}
]
}

```

 

# 間違った解決策

## Webコンソール ではなくブラウザーコンソールを開く

 FireFoxのwebextensionsのconsole.log()メッセージはF12キーで開くWebコンソールではなく、Ctrl+Shift+Jで開くブラウザーコンソールに表示される、らしい。

https://qiita.com/mouseofmicky/items/05dc51f792e16e25ae29 

Fコレ自体が相当にFireFox固有の落とし穴感があるが、こちらをチェックしていてもやはりログメッセージは出力されない。


 

また、開発ツールのコンソール(一時的な拡張機能の読み込み>調査 ボタンから開く )もあるが、こちらにも表示されない。これはbackgroundのメッセージが表示される(のだったと思う)。



## document.addEventListener('DOMContentLoaded', ~)

そもそもcontent_scriptsがデフォルトでページ読み込みが完了したこのあたり(雑)のタイミングで読み込まれるものであるし、console.log()の出力成否はページの描画状況とは関係ない。

 

## document.body.appendChild(elemDebugMsgOnDisplay);

console.logが出ないならDOMでページ上に直接出してしまえばいいじゃない、のアプローチ。

content_scriptsが走っていないので DOM書き換えが行われず、うまくいかない。

 

# 解決策

manifest v2(MV2)に変更する。

```

{
"manifest_version": 2,

```
 

# おわりに

FireFoxはまだMV3未対応できちんと動かないなら、最初から読み込まないとか、動かないというエラーログを出してほしい。

 

Blenderでレンダリング画像の色がおかしい場合の対処

レンダリング結果の画像が編集画面と一致せずおかしくなる場合が有ります。

編集画面ではこれで、

 レンダリング結果の色がおかしくなっています。


原因はWorldの背景色が反射でオブジェクトに映っているためです。

 Scene>Surface>Color から設定できます。

また右上のViewを選択することでRenderingプレビューで表示して編集することもできます。

またViewの設定ではSceneWorldのチェックを外すと背景色がオブジェクトに映らなくなります。

 


以上です。

Blenderクイズ:SubdivisionSurfeceの結果がおかしい

(今回、持って回った英文翻訳風にざっくり雑にブログ記事を書きたい気持ちだったのでクイズの形式を取っているだけです。答えバレ防止反転表示などはしていないので、本当にクイズ当てしようとせず、軽い気持ちで読んでください。)   3Dモデリングソフトウェアは立体という我々が日常に何時も触...