Photoshop プラグイン参考

中綴製作所 DTP スクリプト研究室
http://nakatoji.lolipop.jp/index.php/extendscript

こちらのサイトさんが凄く勉強になる。
スクリプトで実現したいことがカテゴリごとに分かれており、とても参考になりました。

アクションをスクリプト化する(Scripting Listener)
http://nakatoji.lolipop.jp/index.php/extendscript/photoshop/ps-misc/448-2018-07-14-03-06-13

ScriptingListener さえ使えれば、たいていのことは実現できる。

Scripting Listener

ScriptListener.8li ファイルを
Program Files/Adobe/Adobe Photoshop 2020/Plug-ins 以下に配置する。そうすると、デスクトップ上に操作を記録した log ファイルが生成される。
使わないときは 8li このフォルダから削除する。

参考リンク

Photoshopのエクステンションを自作する
https://www.tam-tam.co.jp/tipsnote/tool/post14513.html

JSXをつかってPhotoShopを自動化する
https://kimizuka.hatenablog.com/entry/2016/08/02/104129

Linux, FreeBSD の elf フォーマット

ELFファイルを作る part1
http://warabanshi.hatenablog.com/entry/2012/11/23/150604

ELFのオブジェクトファイル形式を生成する
https://tyfkda.github.io/blog/2020/04/20/elf-obj.html

a.out と elf

今は、elf ファイル形式が使われているというのは知っていたが、gcc が出力するのは a.out ???というのが疑問だったが、下記ページで解決。

余談
生成されたファイル「a.out」は、あたかもファイル形式のa.out形式と関係ありそうですが、しかし、じつはファイル形式の a.out形式 とは無関係です。過去にa.out形式というファイル形式が存在していた時代があり、その名残り(なごり)で生成ファイル名がa.outのままになっています。 実際の生成ファイルのファイル形式は、ELF形式などの別の形式であるのが普通です。

https://ja.wikibooks.org/wiki/C%2B%2B/%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB

非常に参考なりました。

Maya と Tangent, Binormal

Tangent は、三角形の頂点座標、法線、UV の値を元に計算される。(Binormal は求めた Tangent と Normal の外積で算出するため、Tangent だけ考えれば良い)

UV 展開をした時、そのポリゴンは UV 座標上で △ ▷ ▽ ◁ など、どのような方向にでも向くことが出来るため、法線マップなどの接空間テクスチャに書かれたベクトルを三角形の表面に貼るには、三角形が法線 z 以外にも、x と y 方向のどちらを向いているかの情報を元にして変換する必要がある。(軸の向きを揃える必要がある)

Albedo の値などは、単に UV から拾ってきた値がそのままピクセルの値になるが、法線マップは接空間上にあり、手前が z、横方向(u) と縦方向(v) という軸で作られている。Albedo と違い法線マップは向きが重要であり、そのままテクセルとして拾った値をポリゴン表面で使おうとすると、ポリゴンの軸の向きが異なっているため、法線ベクトルも意図した向きになってくれない。そのため取得した法線の値とポリゴンの向きを揃えるために、float3x3(Tangent, Binormal, Normal) の値を使って変換をかける必要がある。

当然、UV の値 (三角形の向き) が異なれば、x 軸、y 軸の値も異なる。別々の UV で法線マップを2枚ブレンドしたい場合などは、Tangent も2つ頂点の値として書き出す必要がある。

Tangent と Binormal の表示

Maya でメッシュの Tangent と Binormal を表示するには、mesh ノードの亜トリビュートで、Mesh Component Display -> Display Tangent を選択。

標準で赤が Tangent。青が Binormal。

参考

付録 A: 接線および従法線ベクトル
https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2018/JPN/Maya-Modeling/files/GUID-169FEA8E-0289-4B12-A181-D7C79FC98BC2-htm.html

あれこれ計算してフリップしたUVを見つける!!
https://kiwamiden.com/find-the-flipped-uv-by-calculating-part1
https://kiwamiden.com/find-the-flipped-uv-by-calculating-part2
Python を使って Tangent, Binormal の取得。そこから法線方向の取得など非常に参考になります。

その12 頂点座標とUV座標から接ベクトルを求めるちょっと眠い話
http://marupeke296.com/DXPS_No12_CalcTangentVectorSpace.html

任意のカラーでハード エッジを表示する
https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2020/JPN/Maya-Modeling/files/GUID-D23D15E0-8E14-4A4F-892E-2413FA58D85A-htm.html


KhronosGroup の glTF

glTF-Sample-Viewer
https://github.com/KhronosGroup/glTF-Sample-Viewer

glTF-Compressonator
https://github.com/KhronosGroup/glTF-Compressonator

参考

https://github.com/KhronosGroup/glTF-Compressonator/tree/master/Compressonator/Applications/_Plugins/C3DModel_viewers/glTF_DX12_EX

https://github.com/KhronosGroup/glTF-Compressonator/tree/master/Compressonator/Applications/_Plugins/C3DModel_viewers/glTF_DX12_EX/DX12Util

https://github.com/KhronosGroup/glTF-Compressonator/tree/master/Compressonator/Applications/_Plugins/C3DModel_viewers/glTF_DX12_EX/DX12Util/shaders

法線マップ周りの覚書

Blending in Detail
https://blog.selfshadow.com/publications/blending-in-detail/
法線マップに、詳細法線マップを足すときの方法

Real-Time Normal Map DXT Compression
https://www.researchgate.net/publication/259000109_Real-Time_Normal_Map_DXT_Compression
法線マップの圧縮方法

Tangent Space Normal Mapping
https://docs.cryengine.com/display/SDKDOC4/Lighting
cryengine の記事

NormalMapCompression
https://github.com/castano/nvidia-texture-tools/wiki/NormalMapCompression

BC5で圧縮された 2ch (x, y) から z を計算する。

z = sqrt(1 - saturate(x*x + y*y))

法線は単位ベクトルなので、長さが 1 になる。
1 = sqrt( x*x + y*y + z*z) を満たす値になるため。

とても参考になりました。

DirectX の座標変換

World matrix

ローカル座標から、ワールド座標へ。

View matrix

ワールド座標から、カメラ(からの相対)座標へ

D3DXMatrixLookAtLH function
https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatlh

zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
    
 xaxis.x           yaxis.x           zaxis.x          0
 xaxis.y           yaxis.y           zaxis.y          0
 xaxis.z           yaxis.z           zaxis.z          0
-dot(xaxis, eye)  -dot(yaxis, eye)  -dot(zaxis, eye)  1

カメラ位置へのワールド行列を求め、その逆行列が View matrix。カメラからの相対座標。

Projection matrix

カメラ位置から、ビューカード内の位置へ。

VS からラスタライザへ

vs で、world -> view -> projection で計算した頂点は下記ような値になり、SV_POSITION として頂点アウトプットしてラスタライザに渡される。

(-1.81066     2.41421342  3.99039908  4.0)
(1.81066    -2.41421342  3.99039908  4.0)
(-1.81066    -2.41421342  3.99039908  4.0)

ラスタライザでは、w と比較してクリッピングを行い、ビューボリューム内に頂点が含まれていることを確認。その後に、Viewport scaling matrix を適用して、描画するレンダーターゲットの位置に変換される。

(700.5888     380.5887792    3.99039908   4.0)
(1859.4112     1539.4112208     3.99039908    4.0)
(700.5888     1539.4112208     3.99039908    4.0)

同次座標のため、w で除算した結果がスクリーン上の座標になる。

(175.1472      95.1471948    0.99759977   1.0)
(464.8528     384.8528052    0.99759977   1.0)
(175.1472     384.8528052    0.99759977   1.0)

https://docs.microsoft.com/en-us/windows/win32/direct3d9/viewports-and-clipping

PS の SV_POSITION に来る値

PS Stage の float4 pos : SV_POSITION で取得できる値は、下記になる。
(175.50, 96.50, 0.9976, 4.0)

XY はスクリーン上の位置、Z は深度バッファに書き込まれる値、W は W

numpy で変換行列周りの確認

import numpy as np

def transform(pos):
    world = np.array(
        [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [1.0, 2.0, 3.0, 1.0]
        ]
    )

    view = np.array(
        [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, -1.0, 5.0, 1.0]
        ]
    )

    proj = np.array(
        [
            [0.75, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.00010002, 1.0],
            [0.0, 0.0, -0.0100010000, 0.0]
        ]
    )

    viewport = np.array(
        [
            [640.0/2, 0.0, 0.0, 0.0],
            [0.0, -480.0/2, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [640.0/2, 480.0/2, 0.0, 1.0]
        ]
    )    
    
    pos = pos.dot(world)
    pos = pos.dot(view)
    pos = pos.dot(proj)    
    pos = pos.dot(viewport)
    print(pos / pos[3])

    
transform(np.array([-1.0, 1.0, -1.0, 1.0]))
transform(np.array([1.0, -1.0, -1.0, 1.0]))
transform(np.array([-1.0, -1.0, -1.0, 1.0]))

参考

https://docs.microsoft.com/en-us/windows/win32/direct3d9/transforms
https://docs.microsoft.com/en-us/windows/win32/dxtecharts/the-direct3d-transformation-pipeline

https://enginetrouble.net/2016/10/reconstructing-world-position-from-depth-2016.html
https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/geometry/row-major-vs-column-major-vector?url=mathematics-physics-for-computer-graphics/geometry/row-major-vs-column-major-vector