<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>最適化 on ながむしメモ</title><link>https://nagakagachi.github.io/categories/%E6%9C%80%E9%81%A9%E5%8C%96/</link><description>Recent content in 最適化 on ながむしメモ</description><generator>Hugo</generator><language>ja-JP</language><lastBuildDate>Sat, 16 Dec 2023 16:11:44 +0900</lastBuildDate><atom:link href="https://nagakagachi.github.io/categories/%E6%9C%80%E9%81%A9%E5%8C%96/index.xml" rel="self" type="application/rss+xml"/><item><title>【UE5】Niagara SimulationStageでNormalMapからHeightMapを復元する(Poisson方程式)</title><link>https://nagakagachi.github.io/entry/2023/12/16/161144/</link><pubDate>Sat, 16 Dec 2023 16:11:44 +0900</pubDate><guid>https://nagakagachi.github.io/entry/2023/12/16/161144/</guid><description>&lt;p&gt;&lt;span&gt;&lt;style&gt;&#10;img{&#10;display: inline-block;&#10;box-sizing: border-box;&#10;border: solid 1px #333;&#10;}&#10;&lt;/style&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Unreal%20Engine"&gt;Unreal Engine&lt;/a&gt; Advent Calendar 2023 の16日の記事です. &lt;a href="https://qiita.com/advent-calendar/2023/ue"&gt;Unreal Engine (UE)&amp;#x306E;&amp;#x30AB;&amp;#x30EC;&amp;#x30F3;&amp;#x30C0;&amp;#x30FC; | Advent Calendar 2023 - Qiita&lt;/a&gt;&lt;/p&gt;&lt;p&gt;最近HoudiniでNormalMapからHeightMapを復元するというものを見かけ,&lt;br /&gt;&#10;Poisson方程式を解くのであればSimulationStageで実装することができるのではと考えました.&lt;blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"&gt;&lt;p lang="ja" dir="ltr"&gt;というわけで、&lt;a href="https://twitter.com/TearsOfJake?ref_src=twsrc%5Etfw"&gt;@TearsOfJake&lt;/a&gt; さんのアド&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9"&gt;バイス&lt;/a&gt;を元に、 &lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%DD%A5%A2%A5%BD%A5%F3%CA%FD%C4%F8%BC%B0"&gt;ポアソン方程式&lt;/a&gt;を用いたノーマルマップからハイトマップの復元。昨日の勾配のみの復元に比べて圧倒的に安定している。 &lt;br&gt;左：入力メッシュ &lt;br&gt;中：入力メッシュから求めたノーマルマップ&lt;br&gt;右：ノーマルマップから復元した高さ情報 &lt;a href="https://t.co/NiNyVvvrbS"&gt;pic.twitter.com/NiNyVvvrbS&lt;/a&gt;&lt;/p&gt;&amp;mdash; &lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Akira"&gt;Akira&lt;/a&gt; Saito (@a_saito) &lt;a href="https://twitter.com/a_saito/status/1721076487150084376?ref_src=twsrc%5Etfw"&gt;2023年11月5日&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt; &lt;/p&gt;&lt;br /&gt;&#10;&lt;p&gt;この記事では「NormalMapからHeightMapを復元する」という問題をSimulationStageで実装する方法を紹介します.&lt;br /&gt;&#10;サンプルプロジェクトは以下のGoogleDriveになります (動作確認バージョン UE5.3).&lt;br /&gt;&#10;&lt;a href="https://drive.google.com/file/d/13X7s09O3bYuvWyIRp3HkDaNOcjrpnOdy/view?usp=sharing"&gt;ReconstructHeightMapFromNormal.zip - Google &amp;#x30C9;&amp;#x30E9;&amp;#x30A4;&amp;#x30D6;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span itemscope itemtype="http://schema.org/Photograph"&gt;&lt;img src="images/811419472fa7cff90fd29f512ec692d5e3a1ed029c96a017cf78f1c960ef9310.png" width="1200" height="657" loading="lazy" title="" class="hatena-fotolife" itemprop="image"&gt;&lt;/span&gt;&lt;/p&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h3 id="Niagara-SimulationStage"&gt;&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Niagara"&gt;Niagara&lt;/a&gt; SimulationStage&lt;/h3&gt;&#10;&lt;p&gt;&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Niagara"&gt;Niagara&lt;/a&gt; SimulationStage はComputeShader的な&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/GPGPU"&gt;GPGPU&lt;/a&gt;処理を&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Niagara"&gt;Niagara&lt;/a&gt;モジュールとして作成できる仕組みです.&lt;br /&gt;&#10;&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Epic%20Games"&gt;Epic Games&lt;/a&gt;公式の&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Niagara"&gt;Niagara&lt;/a&gt; Fluids等でも多用されています(本当にSimulationStageでほとんどの処理が作られています まじかよ).&lt;/p&gt;&lt;p&gt;SimulationStage は2D/3Dのグリッド構造に対する&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/GPGPU"&gt;GPGPU&lt;/a&gt;処理を比較的簡単に作ることができるように設計されています.&lt;br /&gt;&#10;これには数値シミュレーションで必要とされる反復実行なども含まれています.&lt;br /&gt;&#10;目的のタスクを適切な形に変形してSimulationStageで実装することで, &lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/GPU"&gt;GPU&lt;/a&gt;による高速な実行が可能になります.&lt;br /&gt;&#10;&lt;span itemscope itemtype="http://schema.org/Photograph"&gt;&lt;img src="images/f98da2e455903354e0d62a7fb3506e1d0408098ff6cc774991c5c248069f90f1.png" width="1200" height="816" loading="lazy" title="" class="hatena-fotolife" itemprop="image"&gt;&lt;/span&gt;&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h3 id="NormalMapからHeightMapを復元する問題"&gt;NormalMapからHeightMapを復元する問題&lt;/h3&gt;&#10;&lt;/div&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h3 id="Poisson方程式"&gt;Poisson方程式&lt;/h3&gt;&#10;&lt;p&gt;ある関数の二階の空間&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%C8%F9%CA%AC"&gt;微分&lt;/a&gt;と別の関数との関係式をPoisson方程式といいます.&lt;br /&gt;&#10;Poisson方程式は離散化によって連立一次方程式へ変形することができ, 連立一次方程式を解く方法は様々に研究されています.&lt;br /&gt;&#10;対象の問題をPoisson方程式, ひいては連立一次方程式の形にすることができれば, Solverや解法を利用して解くことができます.&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(\Delta \phi =-\dfrac{\rho}{\epsilon_0}\)&lt;/span&gt;&lt;br /&gt;&#10;&lt;/p&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h4 id="Poisson方程式への変形"&gt;Poisson方程式への変形&lt;/h4&gt;&#10;&lt;p&gt;今回は NormalMapとHeightMapの関係をPoisson方程式で表現して離散化, 連立一次方程式として解くことにします.&lt;/p&gt;&#10;&lt;p&gt;NormalMapのxy成分はHeightMapの空間&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%C8%F9%CA%AC"&gt;微分&lt;/a&gt;(勾配)から求められます.&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(N_x(x,y)= -\dfrac { \partial H(x,y)}{\partial x}\)&lt;/span&gt;&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(N_y(x,y)= -\dfrac { \partial H(x,y)}{\partial y}\)&lt;/span&gt;&lt;br /&gt;&#10;さらにそれぞれ x, y で&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%CA%D0%C8%F9%CA%AC"&gt;偏微分&lt;/a&gt;します.&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(\dfrac {\partial N_x(x,y)}{\partial x}= -\dfrac { \partial^2 H(x,y)}{\partial x^2}\)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(\dfrac {\partial N_y(x,y)}{\partial y}= -\dfrac { \partial^2 H(x,y)}{\partial y^2}\)&lt;/span&gt;&lt;br /&gt;&#10;ここで上の式はPoisson方程式の形になっています.&lt;/p&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h5 id="差分方程式"&gt;差分方程式&lt;/h5&gt;&#10;&lt;p&gt;このPoisson方程式を離散化すると以下のようになります.&lt;br /&gt;&#10;(&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%C5%EC%B3%A4%C2%E7%B3%D8"&gt;東海大学&lt;/a&gt;理学部遠藤研究室さんのページ等がわかりやすいです. -&gt; &lt;a href="https://teamcoil.sp.u-tokai.ac.jp/lectures/EL1/Poisson/index.html"&gt;&amp;#x96FB;&amp;#x78C1;&amp;#x5834;(SP)&lt;/a&gt; )&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(\frac {N_x(x+h,y) - N_x(x-h,y)}{2h}= -\frac {H(x+h,y)+H(x-h,y) - 2H(x,y)}{h^2}\)&lt;/span&gt;&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(\frac {N_x(x,y+h) - N_x(x,y-h)}{2h}= -\frac {H(x,y+h)+H(x,y-h) - 2H(x,y)}{h^2}\)&lt;/span&gt;&lt;br /&gt;&#10;(左辺は中心差分)&lt;/p&gt;&lt;p&gt;2つの式を足して左辺のNormalMap, 右辺にHeightMapに関わる項をまとめて整理します.&lt;br /&gt;&#10;またテクセルでの&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/%C8%F9%CA%AC"&gt;微分&lt;/a&gt;(差分)のため &lt;span class="math-inline"&gt;\(h = 1\)&lt;/span&gt; とします.&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(- \frac {N_x(x+1,y) - N_x(x-1,y) + N_x(x,y+1) - N_x(x,y-1)}{2} \\= H(x+1,y)+H(x-1,y) + H(x,y+1)+H(x,y-1) - 4H(x,y)\)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;上の式の左辺は入力NormalMapとして与えられる既知の値, 右辺は求めたいHeightMapのいくつかの地点の値に係数をかけたものの和です.&lt;br /&gt;&#10;よってこれは左辺を定数&lt;span class="math-inline"&gt;\(b\)&lt;/span&gt;, 未知のHeightMapを&lt;span class="math-inline"&gt;\(x\)&lt;/span&gt;, 近傍HeightMap値への係数を行列&lt;span class="math-inline"&gt;\(A\)&lt;/span&gt;とした連立一次方程式ということになります.&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(b = Ax\)&lt;/span&gt;&lt;/p&gt;&#10;&lt;p&gt;連立一次方程式を解くために更に変形していきます.&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h5 id="Jacobi法"&gt;Jacobi法&lt;/h5&gt;&#10;&lt;p&gt;見通しをよくするために左辺は記号で置き換えておきます.&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(-N_{d} = H(x+1,y)+H(x-1,y) + H(x,y+1)+H(x,y-1) - 4H(x,y)\)&lt;/span&gt; &lt;br /&gt;&#10;(ここで &lt;span class="math-inline"&gt;\(N_{d} =\frac {N_x(x+1,y) - N_x(x-1,y) + N_x(x,y+1) - N_x(x,y-1)}{2}\)&lt;/span&gt; )&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(H(x,y)\)&lt;/span&gt; に関する形に変形します.&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(H(x,y) = \frac{(H(x+1,y)+H(x-1,y)+H(x,y+1)+H(x,y-1)) + N_{d} }{4}\)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;この式を反復的に計算することで &lt;span class="math-inline"&gt;\(H(x,y)\)&lt;/span&gt; を解に近づけていく方法をJacobi法といいます.&lt;br /&gt;&#10;プログラム的に考えると&lt;strong&gt;HeightMapの各テクセルについて上下左右の近傍値とNormalMapの値を使って更新&lt;/strong&gt;しているといえます.&lt;br /&gt;&#10;現在のHeightMapから次のHeightMapの各テクセルを並列に計算できるため&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/GPGPU"&gt;GPGPU&lt;/a&gt;とも相性が良いです.&lt;br /&gt;&#10;次はJacobi法によるHeightMapの計算を&lt;a class="keyword" href="https://d.hatena.ne.jp/keyword/Niagara"&gt;Niagara&lt;/a&gt; SimulationStageで実装します.&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;</description></item><item><title>Voxel Mesh化手法についてメモ( Voxel Meshing )</title><link>https://nagakagachi.github.io/entry/2020/08/22/180515/</link><pubDate>Sat, 22 Aug 2020 18:05:15 +0900</pubDate><guid>https://nagakagachi.github.io/entry/2020/08/22/180515/</guid><description>&lt;p&gt;SDFなどのVoxelからMeshを生成する手法のメモ。&lt;/p&gt;&#10;&lt;p&gt;もとのSDFのセルと、Mesh化で管理されるVoxelは一致しないので注意。&lt;/p&gt;&#10;&lt;p&gt;もとのSDFのセル中心を頂点とするようなVoxel上でMesh化が実行される。&lt;/p&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h3 id="marching--cubes"&gt;Marching Cubes&lt;/h3&gt;&#10;&lt;p&gt;&lt;a href="http://paulbourke.net/geometry/polygonise/"&gt;Polygonising a scalar field (Marching Cubes)&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;Voxelの頂点のパターンからそのVoxelのポリゴンパターンをLookupしてMesh化する。&lt;/p&gt;&#10;&lt;p&gt;シャープな形状が作りにくいらしい。&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h3 id="dual-contour"&gt;Dual Contour&lt;/h3&gt;&#10;&lt;p&gt;&lt;a href="https://people.eecs.berkeley.edu/~jrs/meshpapers/SchaeferWarren2.pdf"&gt;https://people.eecs.berkeley.edu/~jrs/meshpapers/SchaeferWarren2.pdf&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;あるVoxelを構成する辺について、SDFをの符号が異なる両端を持つ辺に注目し、辺を横切るような等値面の交差位置と法線をSDFの勾配等から計算する。&lt;/p&gt;&#10;&lt;p&gt;一つのVoxelについて境界面は複数存在する可能性があり、すべての境界面からの距離の自乗和が最小になるような一点をそのVoxel内の頂点として最小二乗法で推定する。&lt;/p&gt;&#10;&lt;p&gt;すべてのVoxelについて上記の点を計算し、隣接Cellで点同士をつなげてMeshを構成する。&lt;/p&gt;&#10;&lt;p&gt;シャープな形状を作ることができるらしい。&lt;/p&gt;&#10;&lt;p&gt;Voxel毎に最小二乗法を解く必要があるためコストが高い可能性。&lt;/p&gt;&#10;&lt;p&gt;また自己交差メッシュができてしまう可能性もある。&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;div class="section"&gt;&#10;&lt;h3 id="surfacenets"&gt;SurfaceNets&lt;/h3&gt;&#10;&lt;p&gt;&lt;a href="https://www.merl.com/publications/docs/TR99-24.pdf"&gt;https://www.merl.com/publications/docs/TR99-24.pdf&lt;/a&gt;&lt;br /&gt;&#10;&lt;a href="https://medium.com/@bonsairobo/smooth-voxel-mapping-a-technical-deep-dive-on-real-time-surface-nets-and-texturing-ef06d0f8ca14"&gt;Smooth Voxel Mapping: a Technical Deep Dive on Real-time Surface Nets and Texturing | by DreamCat Games | Aug, 2020 | Medium&lt;/a&gt;&lt;br /&gt;&#10;&lt;a href="https://github.com/TomaszFoster/NaiveSurfaceNets/blob/master/NaiveSurfaceNets.cs"&gt;NaiveSurfaceNets/NaiveSurfaceNets.cs at master &amp;middot; TomaszFoster/NaiveSurfaceNets &amp;middot; GitHub&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&#10;&lt;p&gt;Meshを構成するVoxel内の頂点を推定することはDual Contourと同様だが、複数ある辺と等値面の交差位置を平均した地点を頂点位置とするところが異なる。&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;a href="https://nagakagachi.hatenablog.com/entry/2020/08/22/180515"&gt;元のはてなブログ記事&lt;/a&gt;&lt;/p&gt;</description></item><item><title>最適化 Newton法メモ</title><link>https://nagakagachi.github.io/entry/2018/07/28/002457/</link><pubDate>Sat, 28 Jul 2018 00:24:57 +0900</pubDate><guid>https://nagakagachi.github.io/entry/2018/07/28/002457/</guid><description>&lt;p&gt;自分の言葉で書いて覚えるため（誤りがあればご指摘ください）&lt;/p&gt;&#10;&lt;br /&gt;&#10;&lt;p&gt; 関数 &lt;span class="math-inline"&gt;\(f(\vec{x})\)&lt;/span&gt; の2次までのTaylor展開&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(f(\vec{x} + \vec{h}) = f(\vec{x}) + dot(\nabla f(\vec{x}), \vec{h}) + \frac{1}{2} dot(\vec{h^T}, \nabla^2 f(\vec{x})\vec{h})\)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;ここで &lt;span class="math-inline"&gt;\(\nabla^2 f(\vec{x})\)&lt;/span&gt; はHesse行列&lt;/p&gt;&lt;p&gt;右辺を最小化にするような&lt;span class="math-inline"&gt;\(\vec{h}\)&lt;/span&gt;によって&lt;span class="math-inline"&gt;\(\vec{x}_{next} = \vec{x} + \vec{h}\)&lt;/span&gt;と更新することで&lt;br /&gt;&#10;&lt;span class="math-inline"&gt;\(f(\vec{x})\)&lt;/span&gt;をより小さくする&lt;span class="math-inline"&gt;\(\vec{x}\)&lt;/span&gt;が得られる。&lt;br /&gt;&#10;そのために&lt;span class="math-inline"&gt;\(\vec{h}\)&lt;/span&gt;で&lt;a class="keyword" href="http://d.hatena.ne.jp/keyword/%C8%F9%CA%AC"&gt;微分&lt;/a&gt;して&lt;span class="math-inline"&gt;\(=0\)&lt;/span&gt;となるような&lt;span class="math-inline"&gt;\(\vec{h}\)&lt;/span&gt;を求める&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(\frac{\mathrm{d} f(\vec{x}+\vec{h})}{\mathrm{d} \vec{h}} = \frac{\mathrm{d} f(\vec{x})}{\mathrm{d} \vec{h}} + \frac{\mathrm{d} dot(\nabla f(\vec{x}), \vec{h})}{\mathrm{d}\vec{h}} + \frac{1}{2} \frac{\mathrm{d} dot(\vec{h^T}, \nabla^2 f(\vec{x})\vec{h})}{\mathrm{d} \vec{h}} = 0\)&lt;/span&gt;&lt;br /&gt;&#10; &lt;br /&gt;&#10;右辺第一項は変数&lt;span class="math-inline"&gt;\(\vec{h}\)&lt;/span&gt;が無いので&lt;span class="math-inline"&gt;\(0\)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;右辺第二項は&lt;a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%E2%C0%D1"&gt;内積&lt;/a&gt;をベクトル&lt;span class="math-inline"&gt;\(\vec{h}\)&lt;/span&gt;で&lt;a class="keyword" href="http://d.hatena.ne.jp/keyword/%C8%F9%CA%AC"&gt;微分&lt;/a&gt;するので&lt;span class="math-inline"&gt;\(\nabla f(\vec{x})\)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;右辺第三項は二次の同次&lt;a class="keyword" href="http://d.hatena.ne.jp/keyword/%C2%BF%B9%E0%BC%B0"&gt;多項式&lt;/a&gt;の二次形式&lt;span class="math-inline"&gt;\(dot(\vec{x^T}, A\vec{x})\)&lt;/span&gt;の&lt;a class="keyword" href="http://d.hatena.ne.jp/keyword/%C8%F9%CA%AC"&gt;微分&lt;/a&gt;なので、&lt;/p&gt;&lt;p&gt;&lt;span class="math-inline"&gt;\(\frac{1}{2} \frac{\mathrm{d} dot(\vec{h^T}, \nabla^2 f(\vec{x})\vec{h})}{\mathrm{d} \vec{h}} = \frac{1}{2} (\nabla^2 f(\vec{x}) + \nabla^2 f(\vec{x})^T)\vec{h}\)&lt;/span&gt;&lt;/p&gt;</description></item></channel></rss>