simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Imagemagick:画像のエッジを引き延ばして格子状に再配置

前書き

キューブの見た目を更新する目的で動いています。

前回は Shader ができたところまで
simplestar-tech.hatenablog.com

今回はテクスチャを連番で結合する処理を作ります。
大分前に python の pillow で画像処理を書きましたが…
github.com
処理が遅すぎるのと
画像のエッジの引き延ばしを行っていなかったので、キューブ群を遠目で見ると結合部分が光ったり黒くなったり…とにかく見た目が良くない
その部分を今回は imagemagick を利用して解決していきます。

参考までに、昔のキューブの見た目は頑張ってこんなの
simplestar-tech.hatenablog.com

もう2年以上、技術選定を続けているという…今年は完成させるぞ!
simplestar-tech.hatenablog.com

Imagemagick の基本を習得

まずは Windows 環境で使えるように portable 版をダウンロードして展開し PATH を通しておきます。
imagemagick.org

以降、Windows 環境だと convert コマンドを magick にしなければバッティングする旨を imagemagick が教えてくれるので
magick コマンドを利用します。
そうしたことを念頭に次のマニュアルを完走して、imagemagick を身体になじませました。

imagemagick.biz

Imagemagick での画像のエッジ引き延ばし

情報ソースはこちら
www.imagemagick.org

細かいことは置いとくと、次の倍率を指定するだけで余白を引き延ばすことができます。
(残念ながら distort は基本操作には出てこない)

magick in.png -set option:distort:viewport %[fx:w*(1+0.05)]x%[fx:h*(1+0.05)] -virtual-pixel Edge -distort SRT "0,0 1,1 0 %[fx:w/(2/0.05)],%[fx:h/(2/0.05)]" out.png

ちょっとだけ解説すると
distort:vieport が left, top 引き延ばし幅に関与&全体の幅高さ倍率指定
virtual^pixel Edge が right, bottom の引き延ばし幅に関与していて、要するに 1 引いた倍率を 1/2 倍で指定というながれ

画像を変換してタイル状に並べる

変換した画像を利用するという小技について、まずはおさらい。
こちらの画像を入力に(昔、自分が描いた絵です)

f:id:simplestar_tech:20200210204717j:plain
in.jpg

こちらの処理を実行すると

magick in.jpg -resize 200x200 -size 300x300 xc:blue +swap -gravity center -compose over -composite -mattecolor red -frame 10x10 exit.jpg

意味は、200x200 にアスペクト比を保ったまま縮小して、blue 一色で塗りつぶした 300x300 の画像を新規作成、並び順を入れ替えて、conposite により青を背景に重ね合わせて、10pixel 幅の赤いフレームを追加
という文(読めました?)

次の結果が得られます。

f:id:simplestar_tech:20200210204915j:plain
exit.jpg

PowerShell で実行する複数ファイル作成とタイリングモンタージュ

以下の powershellWindows 環境で imagemagick に PATH が通っていれば動きます。

テクスチャはこちらの有料アセット(single entity license)を購入したものを利用します。
Yughues PBR Nature Materials
assetstore.unity.com

tga ファイルは magick で変換すると上下逆転しますし、Specular は png に tga から変換すると背景色が真っ白に変わるので(本当は黒)
一度 jpg に中間ファイルを出して、上下反転しつつもなんとか
あと、ファイルによっては正方形ではないので正方形に直します。
加えて、左右に 8 pixel の余白を設けるように 1008 x 1008 に圧縮してタイリングしたいと思います。

を実現する Powershell が以下の通り

# [AO, Diffuse, Height, Normal, Specular]
$target = "Specular"
New-Item $target -ItemType Directory -Force
$dir = "~\Assets\Yughues PBS Nature Materials"
$imgs = Get-ChildItem -Recurse -Path "$dir\*$target.tga"
foreach ($img in $imgs) {
    $fullName = $img.FullName
    $jpg = "$target\" + [io.path]::ChangeExtension($img.Name, "jpg")
    $id = identify $fullName
    $edge = 0.0158730
    if ($id -like "*512x1024*") {
        magick $fullName -resize 504x1008 -flip -write mpr:i +delete mpr:i mpr:i +append -set option:distort:viewport "%[fx:w*(1+$edge)]x%[fx:h*(1+$edge)]" -virtual-pixel Edge -distort SRT "0,0 1,1 0 %[fx:w/(2/$edge)],%[fx:h/(2/$edge)]" -quality 100 $jpg
    }
    else {
        magick $fullName -resize 1008x1008 -flip -set option:distort:viewport "%[fx:w*(1+$edge)]x%[fx:h*(1+$edge)]" -virtual-pixel Edge -distort SRT "0,0 1,1 0 %[fx:w/(2/$edge)],%[fx:h/(2/$edge)]" -quality 100 $jpg
    }
    echo $jpg
}
montage "$target\*$target.jpg" -tile 8x8 -geometry 1024x1024 "0_$target.png"

出力されるテクスチャを使って、Height map を利用しつつ絵を作ることができました。

f:id:simplestar_tech:20200211123626p:plain
8x8 の 64 分割テクスチャによる 1 マテリアル描画で全キューブ描画

ステップ2はクリアです。
残すはゲーム内の UV 操作のみ

追記

余白をエッジ引き延ばしするのもよかった
だけど parallax で使う場合はかなり余白を利用することになるし、そこがエッジ引き延ばしだとまた不自然な見た目になったので
リピートラッピングする方法を考案しました。

次の命令は画像の上下左右ななめ方向すべてにタイリングする例です

magick in.jpg -resize 960x960 -flip -write mpr:i +delete mpr:i mpr:i mpr:i +append -write mpr:j +delete mpr:j mpr:j mpr:j -append -gravity center -crop 1024x1024+0+0 -quality 100 out.jpg

これをスクリプトにつなげると

# [AO, Diffuse, Height, Normal, Specular]
$target = "Diffuse"
New-Item $target -ItemType Directory -Force
$dir = "D:\github\Unity\UniversalParallaxOffset\Assets\Yughues PBS Nature Materials"
$imgs = Get-ChildItem -Recurse -Path "$dir\*$target.tga"
foreach ($img in $imgs) {
    $fullName = $img.FullName
    $jpg = "$target\" + [io.path]::ChangeExtension($img.Name, "jpg")
    $id = identify $fullName
    if ($id -like "*512x1024*") {
        magick $fullName -resize 480x960 -flip -write mpr:i +delete mpr:i mpr:i +append -write mpr:j +delete mpr:j mpr:j mpr:j +append -write mpr:k +delete mpr:k mpr:k mpr:k -append -gravity center -crop 1024x1024+0+0 -quality 100 $jpg
    }
    else {
        magick $fullName -resize 960x960 -flip -write mpr:j +delete mpr:j mpr:j mpr:j +append -write mpr:k +delete mpr:k mpr:k mpr:k -append -gravity center -crop 1024x1024+0+0 -quality 100 $jpg
    }
    echo $jpg
}
montage "$target\*$target.jpg" -tile 8x8 -geometry 1024x1024 "0_$target.png"

期待通り