Metal 関係覚書

たまにしか使わないので基本概念が抜けがち。

シェーダー

具体的には ***.metal ファイルがそれ。
頂点データと色の処理を決めているファイル。これだけだと有り難みがピンとこないが、実際にはこれが(並列処理可能な) GPU で処理される、というのがミソ。
このおかげで、頂点が増えれば増えるほど、効率的な処理ができるようになる。

なお、この時、使用される言語が MSL (Matal Shading Language)。

Metal は OpenGL とは違い、***.metal ファイルはビルド時にプリコンパイルされれる(.metallib というファイルが生成される)。OpenGL では実行時にコンパイルされるので、この点も高速化に貢献してそう。

 

Metal 公式サンプル

アップルが公開している Metal の公式サンプルで気になったプロジェクトなど。

CAMetalLayer 関係

CA というのがわからなかったが、Core Animation のことらしい。
興味深くはあるが、私はあまり使わないかな。

Ray Tracing と InterSection を組み合わせたプロジェクト

綺麗だ。。。

が、ここら辺までくると文字ベースの解説は一切なし。
動画はあるけど。

2D texture 関係

特にサンプルは挙げられていないが、取り扱うデータによって何を採用したらいいのか?みたいなことがこの記事に書いてある。

具体的なサンプルとしては、とりあえず

https://developer.apple.com/documentation/metal/onscreen_presentation/reading_pixel_data_from_a_drawable_texture?language=objc

https://developer.apple.com/documentation/metal/textures/creating_and_sampling_textures?language=objc

の二つをチェック。

前者は、ビルドするとこんなウィンドウが表示される。

ドラッグすると、ドラッグした領域をデスクトップ上にファイルの形で切り出してくれる。
MTKView 上でマウスの位置に応じてちょっと工夫した処理を行いたい、なんてときに使えるかもしれない。

後者は、これ。

 

かなり以前からある基本的なプロジェクトでした。

が、今から思うとこれはこれで使い道ありそう。

(続く)

 

Metal がよくわからんという人は公式サンプルから入るといいと思う

以前に「Metal 入門」という記事を書いたことがあるのだが、Metal 関係の情報は乏しいせいかネット上ではかなり参照されているようだ。

放置するのもなんなので、先日、Metal を仕様する際に出てくる「コマンド」に関して追記した。

そこで提示したサンプルは Objective-C にするのか Swift にするのか迷ったのだが、結局、Swift にした。

じゃあ、Objective-C ではどうやるのってのが本記事。

Objective-C で書かれたサンプルは本当に少ないが、Objective-C から Metal を使いたい人は公式にあるサンプルあたりから入るといいと思う。

お馴染みの三角形を描くサンプルもある。

ただし、同一プロジェクトに iOS と tvOS のターゲットも同包されているので、MacOS だけ取り出しておいた方がわかりやすい。

こんな感じになる。

以下、このサンプルに関して注意点などメモ。

MTKView の設定

View は MTKView にする必要があるが、Xcode の操作性がイマイチで、手動で MTKView に設定する必要がある。

ViewPort

ところで、今回のサンプルでは、ウィンドウのサイズを変えても描画される三角形の大きさは変わらない。

これは ViewPort を使うことで以下のように実現している。

内部的には、ウィンドウに何らかの変化が起こると delegate の以下のメソッドが呼び出されている。

/// Called whenever view changes orientation or is resized
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
    // Save the size of the drawable to pass to the vertex shader.
    _viewportSize.x = size.width;
    _viewportSize.y = size.height;
}

要するに実際のウインドウのサイズを ViewPort のサイズとして引き渡しているわけですね。

この情報はシェーダーで以下のように処理されている。

    out.position.xy = pixelSpacePosition / (viewportSize / 2.0);

Metal の使用する座標系を実際のウィンドウの大きさで割ることで、描画する図形の大きさを一定に保っているという理屈です。

単純に三角形を描画させたいだけであれば、頂点のデータは

    static const PHVertex triangleVertices[] =
    {
        // 2D positions,    RGBA colors
        { {  1.0,  -1.0 }, { 1, 0, 0, 1 } },
        { { -1.0,  -1.0 }, { 0, 1, 0, 1 } },
        { {    0,   1.0 }, { 0, 0, 1, 1 } },
    };

などと Metal 本来の座標系に準じて設定。
シェーダーも

    //out.position.xy = pixelSpacePosition / (viewportSize / 2.0);
    out.position.xy = pixelSpacePosition;

としてしまえば、三角形はウィンドウの大きさに従って変化します。

描画色に変化をつけてみる

私は試してないが、『シェーダーにランダムな値を送って動きをつける』あたりを参照して、改変するといいと思う。

ソースコードはこちらで。

回転させる、遠近処理をつける

詳しい解説はしないが、それなりの改変を加えると回転や遠近処理もできる。

その入り口くらいまではこちらの記事で軽く説明しています。
よろしければご一読ください。

 

 

【Mac】ハロワールドっぽいページを複数作って遷移の確認【Servlet】

tomcat 環境ができたので、簡単な動作確認用のコードを書いてみた。
使用したコードは GitHub で公開してますので、ポイントだけ解説していきます。

 

新しい環境になれる際にやることは、大抵、ハローワールドだと思う。
が、Web アプリの場合、実務的に重要なのはデプロイ時の
・コンテキストルートの癖
・url mapping の設定
あたりになってくると思うので、この点を意識して(いきなりだが)サーブレットファイルを3つ用意してみた。
ファイル1つだけだと遷移できるかどうか確認できないので。
だから、3ファイルには相互にリンクを張って狙った通りに遷移できるか試そうという意図です。

このうちの1つのファイルがこれ(Page1.java)。
シンプルな .html になるが、他の2つのページへのリンク入れてますね。

package info.phazor.link;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Page1 extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();

    out.println("<html>");
    out.println("<head>");
    out.println("<title>link test"</title>);
    out.println("</head>");
    out.println("<body>");

    out.println("<p>テストページ1</p>");

    out.println("<p><a href=\"/link-1.0/page2\">テストページ2へ</a></p>");
    out.println("<p><a href=\"/link-1.0/page3\">テストページ3へ</a></p>");

     out.println("</body>");
     out.println("</html>");
   }
}

リンクの張り方を適当に変えて Page2.javaPage3.java も作成。
Mac なのでエスケープ文字は \ を使ってますが、windows の場合は ¥(半角)使えばコンパイル通ると思います。

これらのサーブレットから生成されるページが、リンク先に指定した URL に正しくマッピングされていないとブラウザ上でリンクをクリックしてもリンク先のページが表示されないことになる。

で、そのマッピングの設定は web.xml が担当している。

今回の場合は、以下(関係箇所を抜粋)のようになる。


    <servlet>
        <servlet-name>Page1</servlet-name>
        <servlet-class>info.phazor.link.Page1</servlet-class>
     </servlet>
    <servlet>
        <servlet-name>Page2</servlet-name>
        <servlet-class>info.phazor.link.Page2</servlet-class>
     </servlet>    
    <servlet>
        <servlet-name>Page3</servlet-name>
        <servlet-class>info.phazor.link.Page3</servlet-class>
     </servlet>
 
    <servlet-mapping>
        <servlet-name>Page1</servlet-name>
        <url-pattern>/Page1</url-pattern>
     </servlet-mapping>
     <servlet-mapping>
        <servlet-name>Page2</servlet-name>
        <url-pattern>/Page2</url-pattern>
     </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Page3</servlet-name>
        <url-pattern>/Page3</url-pattern>
     </servlet-mapping>

要するに
・上の3段でサーブレットの名前とクラスを対応づけ
・下の3段でサーブレットと URL を対応づけ
ているわけですね。

これで、生成したページとURLをマッピングさせているわけですね。

tomcat 上で動作させましたが、割とさくさく遷移してくれました。

あとは静的なファイルを用意して、これらの集積でサイトが構築できる、という理屈のようです。

Java のこういったクセのないアプローチはさすが Java って感じですね。
まあ、たぶん、アノテーションなどを使った「モダン」な書き方もあるんでしょうが(苦笑)。

なお、GitHub リポジトリにある link2 は、上のコードにユーザー認証(session を使ったパスワード認証)を付け加えたものです。

 

猪股弘明