モデリングしたオブジェクトをProcessingでトゥーンシェーディングする方法

#はじめの諸注意
この記事は、Magicavoxelを用いたモデルにProcessingを用いてトゥーンシェーディングをした記事、結果内容とその補足を記述しています。
また、本記事が**筆者の初投稿記事＆シェーダー初心者**なため、ちゃんとやっている人にとってはところどころ認識の間違いがあるかとは存じますが、記事通りの進行方法で進めれば、**きちんとトゥーンシェーディングできるようになっております。**
もし、下記に記す内容に誤りなどがございましたらご指摘いただけますと幸いです。

#使用したソフトウェア

・**Processing**…みなさまご存じ、軽い演算処理やデジタルアートなど様々な用途に使われているソフトウェアです。このソフトウェアがないと何も始まりません。
（URL）「Processing ダウンロードサイト」https://processing.org/download/

・**MagicaVoxel**…ボクセルモデリングをすることが出来るソフトウェア。この記事ではこのソフトウェアを用いて制作したモデルにシェーディングしていきます。
（URL）「Magicavoxelダウンロードサイト」https://ephtracy.github.io/#ss-carousel_ss

・**Shdr Editor**…ブラウザ上でGLSLを記述することで、実行結果を即座に反映してくれるサービスです。
（URL）「Shdr Editor」https://shdr.bkcore.com/

・**メモ帳**…パソコンに内蔵されているメモ帳アプリで結構です。GLSLシェーダーを記述するために必須です
#実行画面(Twitter)
https://twitter.com/Nessponn_Game/status/1285960765233524736

###コード
```java:ToonShader.pde
//使いたいモデルやシェーダーは事前に
//「スケッチ」→「ファイルの追加」で入れておく

PShape model;
PShader shader;

float angle;

void setup(){
  size(960,720,P3D);
  
  model = loadShape("mygirl.obj");//モデルのインポート
  shader = loadShader("texfrag.glsl","texvert.glsl");//シェーダーのインポート
  //glslファイルを２つに分けて行うことを推奨
  //フラグメントシェーダー、頂点シェーダーの順で入れないとエラーが発生します。
}

void draw(){
  
  background(100, 100, 100);
  camera(-400, -250, 150, 0, -170, 0, 0, 1, 0);
  fill(255, 0, 0);
  
  push();
    rotateY(angle += 0.02);
    translate(400,-300,0);
    directionalLight(255, 255, 255, 1, 0, 0);
  pop();
  
  scale(100,-100,100);
  shader(shader);
  shape(model);
}
```
```glsl:texflag.glsl
//フラグメントシェーダー
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

#define PROCESSING_TEXLIGHT_SHADER

uniform sampler2D texture;

varying vec4 vertColor;
varying vec3 vertNormal;
varying vec4 vertTexCoord;
varying vec3 vertLightDir;

void main() {
  
  float nl = max(0.0,dot(vertNormal, vertLightDir));
  if( nl <= 0.01 ) nl = 0.5;
  else if( nl <= 0.3) nl = 0.7;
  else nl = 1.0;
  
  gl_FragColor = vec4((texture2D(texture, vertTexCoord.st).xyz * vertColor.xyz)*nl,1);
}
```
```glsl:texvert.glsl
//頂点シェーダー
uniform mat4 transform;
uniform mat3 normalMatrix; 
uniform vec3 lightNormal;

uniform mat4 texMatrix;

attribute vec4 vertex;
attribute vec4 color;
attribute vec3 normal;
attribute vec2 texCoord;

varying vec4 vertColor;
varying vec3 vertNormal;
varying vec4 vertTexCoord;
varying vec3 vertLightDir;

void main() {
  gl_Position = transform * vertex;

  vertColor = color;
  vertNormal = normalize(normalMatrix * normal);
  vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
  vertLightDir = -lightNormal;
}
```

##MagicaVoxelで作成したモデルをProcessingにインポートする
MagicaVoxelおよび３DCG制作ソフトで作ったモデルを「obj形式」で保存してください。

MagicaVoxelでの手順を説明します。
MagicaVoxelウィンドウ右下に「export」とある箇所があります。そこをクリックしてください
![１.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602533/ee4c35d5-6d64-232f-fd0f-328ea74c3aa6.jpeg)

すると、いくつかの保存形式を選べるパネルが表示されるので、パネル左上の「obj」形式で保存をしてください。（名前は自由で結構です）
![２.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602533/3597c524-d50c-ef0d-f610-6fe586a84f17.jpeg)

そうしたら、「obj」「mtl」「png」の３つの形式ファイルがそれぞれ生成されていれば大丈夫です。
![３.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602533/47288f07-6981-4d2b-2b2e-279f53ea02ae.jpeg)

あとは生成した３つのファイルをProcessingの「スケッチ」→「ファイルの追加」で一つづつorまとめて追加でインポート完了です。

もしエラーが出た場合、３つのうちいずれかのファイルがスケッチのファイル追加で追加されていない可能性があるかもしれません。

##GLSLファイルの作り方&インポートの仕方

GLSlファイルを作成する場合、既存のメモ帳アプリに上記の「texvert.glsl」または「texflag.glsl」のコードをコピペしてください。
「名前をつけて保存」で**コピペした方のタイトルを一字一句間違えないように入力してください。**
この時、**拡張子として語尾に「.glsl」と記述してあるか**、**「ファイルの種類」は「すべてのファイル」に変更されているか**を確認してから保存をしてください。
![４.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602533/c6bdceda-99a8-d7f7-4842-8b7d40d33fe5.jpeg)




##モデルではなく既存の球体などのオブジェクトにシェーディングする方法
例えば外部からモデリングしたものをシェーディングするのではなく、既存のsphere、boxなどのメソッドを用いてシェーディングを行う場合、そのまま上記の「texflag.glsl」を用いるとエラーが起きてしまいます。


この場合、上記に記したフラグメントシェーダーの

```glsl:texflag.glsl
#define PROCESSING_TEXLIGHT_SHADER
///
（省略）
///
gl_FragColor = vec4((texture2D(texture, vertTexCoord.st).xyz * vertColor.xyz)*nl,1);

```
を

```glsl:texflag.glsl
#define PROCESSING_LIGHT_SHADER
///
（省略）
///
gl_FragColor = vec4(vertColor.x * nl,vertColor.y * nl,vertColor.z * nl,1);

```
に変更してから
**「ToonShader.pde」のdraw()内に「noStroke();」を記述する**ことで
適用することが出来ます。

####実行結果
![５.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602533/d8cb5ebf-dbbf-9cf6-be54-4bf400d50d42.jpeg)

#参考文献
https://processing.org/tutorials/pshader/
processingのシェーダーについての公式リファレンスです。ここからさらに発展させたい方はここを読んでください。全文英語ですがそこは頑張って読んでください。

http://www.mlab.im.dendai.ac.jp/~tomoriya/wiki/?%A5%E1%A5%C7%A5%A3%A5%A2%B1%E9%BD%ACC%28CG%29/%C2%E86%B2%F3
先駆者様のトゥーンシェーダーについての記事です。こちらも閲覧いただけるとより理解が深まると思われます。

https://core.ac.uk/download/pdf/295592183.pdf
GLSLでのテクスチャのアタッチの仕方はこちらを参考にいたしました。こちらも全文英語となっております。

##あとがき
始めて書いた記事なので、分かりづらい部分、説明不足な部分などがありましたら、コメントの方などで記述していただけますと幸いです。