【ShaderLab】ディレクショナルライトの方向はどこを向いている?

UnityのShaderLabでライティングをしているとき、ライトの方向ベクトルってどっち向いてるんだろうと思って色として表示してみました。

まぁライティングの結果を見れば想像はできるのですが、もっと愚直に確かめないとしっくりこない子なのです。

half4 LightingSimpleLambert(SurfaceOutput s, half3 lightDir, half atten) {
      fixed4 c;
      c.rgb = lightDir; // ライトの方向をそのまま色として表示
      return c;
    }

f:id:kazumichi96:20210217042815p:plain f:id:kazumichi96:20210217042849p:plain f:id:kazumichi96:20210217042837p:plain

結果はご覧の通りで、シーン上で見えている向きとは逆向きのベクトルとして渡されてくる。

モデルの法線と内積をとる場合は、この方が都合がいいので 一般的にはこうなっている。

ShaderLabでもそうなっていましたという確認。

TypeScript+webpackでブラウザでもNodeでも動くライブラリを作るメモ

ブラウザで動く事は確認したけど、Node環境でうまくいくかの動作検証はできてない状態

概要

webpackを使ってTypeScriptで書かれたライブラリをブラウザ向け、もしくはNode向けにバンドルしようと思ってあれこれしてみた備忘録

webpack.config.jsでoutputの設定をごにょごにょするだけでもある程度行けるが

型定義ファイルとかちゃんと用意しようとすると一筋縄ではいかなかったので

そのあたりについて記載する。

入れたパッケージは以下 - webpack - webpack-cli - typescript - ts-loader

webpack.config.json

とりあえずwebpack.config.jsの中身

const path = require('path');

//-----------------------------------------------------------------------------
// コマンドライン引数には以下の値を指定する
// --mode: development or production
// --type: browser or node
//-----------------------------------------------------------------------------
module.exports = (env, argv) => {

  // コマンドライン引数による判定
  const mode = (argv.mode === undefined)? "production" : "development";
  const isDev = mode === "development";
  const type="node";

  // ブラウザ用の設定
  const browser = {
    path: path.join(__dirname, '/browser'),
    filename: (isDev)? "mylib.js":"mylib.min.js",
    configFile: "tsconfig.json",
  };

  // Node環境用の設定
  const node = {
    path: path.join(__dirname, "/dist"),
    filename:"index.js",
    configFile: "tsconfig.node.json"
  };

  // argv.typeにはbrowserかnodeのどちらかを指定する。指定しないと多分エラーになる
  const params = {browser, node}[argv.type];

  console.log(params);

  const conf = {
    mode: mode,

    entry: './src/index.ts',
    output: {
        path: params.path,
        publicPath: '/',
        filename: params.filename,
        library: 'MyLib',
        libraryExport: '',
        libraryTarget: 'umd',
        globalObject: 'this',
    },
    module: {
        rules: [{
            test: /\.ts$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'ts-loader',
                options: {
                  configFile: params.configFile
                }
              }
            ]
        }]
    },
    // import 文で .ts ファイルを解決するため
    // これを定義しないと import 文で拡張子を書く必要が生まれる。
    // フロントエンドの開発では拡張子を省略することが多いので、
    // 記載したほうがトラブルに巻き込まれにくい。
    resolve: {
      // 拡張子を配列で指定
      extensions: [
        '.ts', '.js',
      ],
    }
  }

  // 開発時のみ
  if (isDev) {
    conf.devtool = 'inline-source-map';
  }

  return conf;
}

まずコマンドライン引数でwebpack --mode development --type browserって感じで

modeとtypeを受け取るようにした。

この引数の内容を見て、webpackの設定を切り替えるようにしている。

outputの設定

    output: {
        path: params.path,
        publicPath: '/',
        filename: params.filename,
        library: 'MyLib',
        libraryExport: '',
        libraryTarget: 'umd',
        globalObject: 'this',
    },

pathは出力先のフォルダで

  • typebrowserが指定された場合は./browser
  • typenodeが指定された場合は./dist

コンパイルしたファイルを出力するようにした。

filenameに関しては

ブラウザ向けの場合、開発時はmylib.js、製品版はmylib.min.jsとなるようにし

Node向けの場合はindex.jsというファイルが生成されるようにした。

libraryに関してはライブラリを作るときにそれっぽい名前にし

libraryTarget: 'umd',
globalObject: 'this',

この設定をしておくことでブラウザでも動作するようにコンパイルされる。

Node向けにビルドする際に.d.tsとかを出す

型定義ファイルを出力するにはtsconfig.jsonの設定が必要だった。

{
   "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
  }
}

このdeclarationdeclarationMaptrueに指定すれば型定義ファイルやマップファイルが出力されるが

これはブラウザ向けの場合は不要なのでtsconfig.jsonを2種類用意した。

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "rootDir": "./src", 
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,   
    "skipLibCheck": true,                    
    "forceConsistentCasingInFileNames": true  
  }
}

tsconfig.node.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    "outDir": "./dist",                        /* Redirect output structure to the directory. */
  }
}

ブラウザ向けビルドの時はtsconfig.jsonが適用され、Node向けビルドの時はtsconfig.node.jsonが適用されるようにwebpack.config.jsの以下の部分に細工している

module: {
    rules: [{
        test: /\.ts$/,
        exclude: /node_modules/,
        use: [
            {
                loader: 'ts-loader',
                options: {
                    configFile: params.configFile
                }
            }
        ]
    }]
},

ts-loaderのオプションで適用するコンフィグファイルを指定できるので、ここでコマンドライン引数のtypeで判定して、適用するコンフィグファイルを変更している。

tsconfig.node.jsonoutDirの指定について

型定義ファイルはoutDirで指定した場所に出力されるので指定している。

これでビルドした結果は予想通りの動きになっていていい感じだ。

ビルドされたjsはブラウザではうまいこと動いている。

あとはこれで作成したものが、他のNodeプロジェクトにインストールしてうまく動くかどうか。

HTMLテンプレートエンジン EJSの主要なメソッド

ejs.render(str, data, options)

EJSのテンプレート文字列とデータを指定してHTMLを生成する関数。

前回の記事で使ったメソッドはこれ。

let ejs = require('ejs');

// テンプレートとデータを用意
const str  = '<%= enemies.join(", "); %>';
const data = { enemies: ['スライム', 'ドラキー', '魔法使い']};

// 描画
const html = ejs.render(str, data);

// 結果を出力
console.log(html);

結果

スライム, ドラキー, 魔法使い

ejs.compile(str, options)template(data)

ejs.render(str, data, options)

という大きく2つの処理をしているっぽい。

ejs.compile(str, options)はEJSテンプレート文字列のコンパイルをする関数で

戻り値にtemplate関数が返ってくるようだ。

このtemplate関数に描画したいデータを渡すとHTMLが返ってくるご様子。

let ejs = require('ejs');

// テンプレートとデータを用意
const str  = '<%= enemies.join(", "); %>';
const data = { enemies: ['スライム', 'ドラキー', '魔法使い']};

// EJSテンプレートのコンパイル
const template = ejs.compile(str);
// データを与えてHTMLを生成
const html = template(data);

// 結果を出力
console.log(html);

ejs.renderFile(filename, data, options, function(err, str){})

これはEJSテンプレートを外部ファイルとして用意しておいて、そのファイルを指定してHTMLを生成する事ができる関数みたい。

ファイル構成

root
 ┣━ index.js
 ┗━ template.ejs

tempalte.ejs

<%= enemies.join(", "); %>

index.js

let ejs = require('ejs');

// テンプレートとデータを用意
const str  = '<%= enemies.join(", "); %>';
const data = { enemies: ['スライム', 'ドラキー', '魔法使い']};
const options = {};

// テンプレートファイルを指定してHTMLを生成
ejs.renderFile("template.ejs", data, options, function(err, str) {
    console.log(err, str);
});

結果

null
スライム, ドラキー, 魔法使い

最終的な結果は第四引数にコールバック関数を渡して受け取る。

コールバックの第一引数にはエラー内容、第二引数に生成されたHTMLが渡ってくる。

主要なメソッドはとりあえずこの3つっぽい

HTMLテンプレートエンジン EJSを触ってみる

EJSはJavaScriptでHTMLを作成する事ができるHTMLテンプレートエンジン。

いろんな記事を見ているとだいたいGulpとセットで使われている記事ばかりだったので

そういう余計なものは使わず、とりあえずEJS単品の動作について見ていこうと思う。

ブラウザでも動作するみたいだけど、ここではNode.js環境を使っている。

インストール

yarn add -D ejs

とりあえず動かしてみる

index.jsを作成:

let ejs = require('ejs');

// 適当なデータを作成
let enemies = ['スライム', 'ドラキー', '魔法使い'];

// ↑で用意したデータを使ってレンダリング
let html = ejs.render('<%= enemies.join(", "); %>', { enemies : enemies });

// 結果を表示
console.log(html);

実行

node ./index.js

結果

スライム, ドラキー, 魔法使い

ejs.render(str, data, options)がEJSのテンプレートで書かれた文字列をHTMLに変換する。

strにはEJSのテンプレート文字列を指定して、dataには描画に使うデータを渡すみたい。

optionsは特に指定していないけど、いろいろ指定できるっぽい。

テンプレートファイルとデータファイルを分けてCLIからHTMLファイルを作る

EJSではテンプレートになるファイルとデータを定義したファイルを別で用意しておいて

CLIからHTMLファイルを作る方法も用意されている。

正直なところ、公式のドキュメントが簡素すぎてもっと説明が欲しい。

ファイル構成

こんな感じでテンプレートとなるファイルとデータファイルを用意してみた。

root
 ┣━ template.ejs
 ┗━ data.json

template.ejs

<%= enemies.join(", "); %>

data.json

{
  "enemies": ["スライム", "ドラキー", "魔法使い"]
}

CLI

npx ejs ./template.ejs -f data.json -o ./output.html
  • コマンドでテンプレートファイルとデータファイルと出力先のファイルを指定して実行。
  • output.htmlが作成される。

output.html

スライム, ドラキー, 魔法使い

ほんとにこれで動くか心配だったけどうまく動いたみたい。

今回はこんなところにして、次回はもう少し細かくEJSについて見ていこう。

Create React App に Reset cssを導入する

create-react-app.dev

ガイドによると

CSSの任意の場所に@import-normalize;を追加して下さい

って書いてある

しかし、追加してみても全然リセットされないんですが!

gist.github.com

仕方ないので別な方法を探した結果、↑の記事を発見。

yarnnormalize.cssをインストールして

index.tsの中でimport 'normalize.cssして

とりあえずできたのでこの方法で行こう。

Create React App 依存関係のインストール

Create React Appで作成したプロジェクトに、追加でパッケージをインストールしてもいいの?

というお話

結論からいうとOK

公式のドキュメントには

他の依存関係を追加したかったら、普通にnpmとかyarnでインストールしても構わないよ

って書いてある

例えばreact-router-domをインストールしたかったら

npm install --save react-router-dom
# or
yarn add react-router-dom

とすればいいみたい