Onoty3D

Unityに関するメモとか

Kuler Islandsでテクスチャ編集用マスクを作る

プロ生ちゃんAdvent Calender 2015 13日目の記事です。

qiita.com

先日、Kuler Islandsというソフトウェアの紹介記事を目にしました。

Kuler Islands - OBJファイルからUVアイランド毎に塗り分けたUVマップを生成出来るツールがGithubにて公開!

3dnchu.com

記事にある通り、「OBJファイルから、UVアイランドで塗り分けたテクスチャ画像を生成する事が出来」るソフトウェアです。

これを見た時「テクスチャ編集時のマスクとして使うのに便利だな」と思いました。
アニメ風テクスチャを作る際など、モデルに同梱されている元のテクスチャに手を加えることが多々あるのですが、テクスチャだけ見るとどこからどこまでがどの部分なのかはっきりとはわかりません。
3Dモデリングツールとか使えば分かるのかもしれませんが、使い慣れていないので…。

というわけでプロ生ちゃんで試してみました。
なおプロ生ちゃんのモデルデータはFBX形式なので、OBJ形式に事前に変換しておく必要があります。
(Kuler IslandsはGitHubで公開されているので、頑張ってFBX形式にも対応させる、という手もある)

FBX→OBJ変換は
Autodesk FBX Converterや、Unity上でやるならObjExporterなどが使えるとおもいます(自分は後者のソースを多少いじって利用)。

ObjExporter - Unify Community Wiki

結果がコレ。

f:id:onoty3d:20151213135455p:plain…。

なるほど。とりあえずFBXをそのままOBJに変換したのですが、SubMeshが複数のテクスチャを参照している場合でも、Kuler Islandsが出力するファイルはひとつになってしまうようです
ならば同一テクスチャを参照しているSubMesh単位でOBJファイルを出力させればうまくいくだろうと思い、ObjExporterのソースを多少いじってやり直し。

結果。うまくいきました。

f:id:onoty3d:20151213131239p:plain

(ちなみにpaddingを1にしています。)

幾つかサンプル。

f:id:onoty3d:20151213135559p:plain

f:id:onoty3d:20151213135624p:plain

全部は以下よりダウンロードできます。
プロ生ちゃんテクスチャ用マスク

ちなみにプロ生ちゃんのSubMeshは22個ありますが、同一テクスチャを参照しているグループでまとめると以下の様な感じになります。
0:skin
1-5,15:dress
6:eyes
7:eyelight
8-11,13,14,18:face
12:eyewhite
16,17,19,20:hair
21:tokei

作成したマスクをプロ生ちゃんのテクスチャとして適用させてみるとこんな感じになりました。

f:id:onoty3d:20151213135735p:plain

胸の話

プロ生ちゃん Advent Calendar 2015 (何でもありの方)  12日目の記事です。

www.adventar.org

 

モデルのボーン名、腕や足なんかはどのモデルもArmやLeg等表現が統一されているのですが、胸は意外とマチマチです。
自分がよく使うモデルたちが、面白いくらいにバラバラだったので、まとめてみました。

社畜ちゃんf:id:onoty3d:20151210195224p:plain

bust

バスト。胸の英語表現としては一番一般的な気がしますね。大人の胸って感じです。

 

ユニティちゃんf:id:onoty3d:20151210195513p:plain

Mune
胸。日本語か!世界に羽ばたくユニティちゃんですが、意外と日本語名が含まれています。

 

クエリちゃんf:id:onoty3d:20151210195540p:plain

Pai
ぱい。ぱい、て。お馬鹿な感じがしていいと思います。

 

中野シスターズf:id:onoty3d:20151210195616p:plain

Chest/Breast
チェストとブレスト。ふたりともChest配下にBreastが設定されてます。
これもまぁ耳にする英単語ですね。
「ちょっと難しい単語使っちゃうぜ、どやぁ」っていう若々しさを感じます。

 

ニコニ立体ちゃんf:id:onoty3d:20151210195735p:plain

tit
チット。こんな単語知りませんでした。お勉強になります。
ひかえめな語感がニコニ立体ちゃんにあってます。

プロ生ちゃんf:id:onoty3d:20151210195819p:plain

(ボーン)がありませんでした。

エディタ拡張機能でプロ生ちゃんを表示する

プロ生ちゃん Advent Calendar 2015 12日目の記事になります。
qiita.com

UnityEditorを起動すると、こんな感じの画面が表示されます。
f:id:onoty3d:20151203192314p:plain
※レイアウトは好きに配置できるので、このとおりとは限りません。

この状態で黙々と作業するには、癒やしが無い。
ということでエディタ拡張機能で、プロ生ちゃんを表示させてみます。

画像はプロ生ちゃんサイトで公開されている素材からお借りします。
pronama.azurewebsites.net

今回はこれ。
f:id:onoty3d:20151203192539p:plain
任意の画像ファイルでよいですが、ファイル名はPronamaChan.png(※)にしてください。
拡張子はjpgとかでも多分大丈夫

早速つくっていきます。

画像はResourcesフォルダに配置すると取得が簡単になるので、
Asstes直下にResourcesフォルダを作り、その下にさらにPronamaChanフォルダを作り、その中に上記のPronamaChan.pngを配置します。
こんな感じ。

Assets
 └Resources
  └PronamaChan
   └PronamaChan.png

エディタ拡張スクリプトはEditorという名前のフォルダの下にPronamachanWindow.csという名前で作成してください。
配置はこんな感じ。

Assets
 └Editor
  └PronamaChan
   └PronamachanWindow.cs

エディタ拡張スクリプトはEditorというフォルダの下であれば、どういう配置でも大丈夫です。
またEditorフォルダもAssetsフォルダ直下で無くても大丈夫です。

エディタ拡張のソースはこんな感じ。

using UnityEditor;
using UnityEngine;

public class PronamaChanWindow : EditorWindow
{
    private Texture2D _texture = null;

    [MenuItem("Window/PronamaChan")]
    private static void Open()
    {
        EditorWindow.GetWindow<PronamaChanWindow>("PronamaChan");
    }

    private void OnGUI()
    {
        if (this._texture == null)
        {
            this._texture = Resources.Load("PronamaChan/PronamaChan") as Texture2D;
        }
        else
        {
            //表示する画像のサイズ
            var textureWidth = (float)this._texture.width;
            var textureHeight = (float)this._texture.height;

            if (this.position.width < textureWidth
                    || this.position.height < textureHeight)
            {
                //現在のWindowサイズより画像のサイズが大きい時

                //縮小率を計算(縦横でより小さい方)
                var shrinkWidth = Mathf.Min(this.position.width / textureWidth, this.position.height / textureHeight);

                //画像のサイズを再設定
                textureWidth *= shrinkWidth;
                textureHeight *= shrinkWidth;

            }

            //画像をWindowの中央に表示するための位置決定
            var posX = (this.position.width - textureWidth) / 2;
            var posY = (this.position.height - textureHeight) / 2;

            //画像の表示
            EditorGUI.DrawPreviewTexture(new Rect(posX, posY, textureWidth, textureHeight), this._texture);
        }
    }
}

表示しているWindowのサイズより画像が大きい場合は、Windowサイズに合わせて画像を縮小表示します。

配置がうまく行っていれば、UnityEditorのWindowsメニューにPronamaChanというメニューが追加されていると思います。
f:id:onoty3d:20151203193135p:plain
これをクリックすると、プロ生ちゃんの画像Windowが表示されます。
f:id:onoty3d:20151203193146p:plain
表示されない場合は配置やファイル名が間違っていないか確認してください。
このまま個別で表示したままでもいいですが、任意の場所にドッキングさせることも可能です。
f:id:onoty3d:20151203193238p:plain

ベースは出来上がったので、これで物足りない人は現在時刻を表示させるようにしたり、日替わりで画像が変わるようにしたり、思い思いにソースを改造してみてください。

先日、別のアドベントカレンダーで結構すごいエディタ拡張が紹介されてましたね…
chroske.hatenablog.com

プロ生ちゃんのMeshを切り分ける

プロ生ちゃん Advent Calendar 2015 9日目の記事です。
qiita.com

以前、Unity5のClothを使って、プロ生ちゃんのスカートをClothシミュレーションする記事を書きました。
onoty3d.hatenablog.com
onoty3d.hatenablog.com

また、Twitter上でプロ生ちゃんが服だけ残してドロンと消える、なんてネタもやりました。

Clothデータの作成は、Meshがはじめからパーツ単位で分かれているモデル(ユニティちゃん等)では楽ですが、プロ生ちゃんモデルはMeshが一つになっているので、別途パーツ単位でMeshを切り分ける必要があります。
プロ生ちゃんに関してはBlender、FBX、PMXデータが公開されているので、3Dモデルが編集できるツールを使えば、切り分けは可能かと思います。
PMXデータからMeshを切り分ける方法は、以下記事で紹介しました。
onoty3d.hatenablog.com

毎度外部ツールを使うのも面倒なので、今回Unityエディタ上でSubMesh単位でMeshが出力できるスクリプトを作成しました(ソースは最後)。
プロ生ちゃん以外にもSkinnedMeshRendererないしMeshFilterを持つオブジェクトから、SubMeshを切り分けできます。
(Meshの任意の部分を切り分けるのではなく、SubMesh単位で切り分けするだけです。)

使い方
1.スクリプトをEditorフォルダ配下に配置すると、UnityエディタのメニューにCustomが増えます。
2.シーン上にプロ生ちゃんモデルを配置して、Hierarchyビューでプロ生ちゃんを選択し、メニューから
Custom>Export>ExportSubMesh(from SkinnedMeshRenderer)を選ぶと、Mesh単位でMeshが出力されます。
f:id:onoty3d:20151208111536p:plain
※複数のオブジェクトを選択していた場合でも、最初のオブジェクのみ処理の対象とします。
※対象オブジェクトに複数のSkinnedMeshRenderer/MeshFilterが適用されている場合でも、最初に見つかったそれからのみSubMeshの切り分けをします。
※出力フォルダは、Assets配下の「選択オブジェクト名+SubSubMeshes」となります。またファイル名は「submesh+連番」となります。
f:id:onoty3d:20151208111548p:plain
これでClothシミュレーションがお手軽になるかと思います。
※高ポリゴンモデルのサブメッシュを分割しようとした場合、マシンスペックにもよると思いますが、非常に時間がかかります。ご注意ください。
プロ生ちゃんモデルでも自分のPCでは10秒ほどかかります。

Clothシミュレーションは、以下記事がとても丁寧で参考になります。
blogs.unity3d.com


以下ソース
【追記:2015/12/13】動いているのかわかりづらいので、プログレスバーの表示を追加しました。
f:id:onoty3d:20151213112429p:plain

【追記:2018/01/18】NormalとTangentの設定をしていなかったので、ソース修正しました。

Unityでコミック風プロ生ちゃん

プロ生ちゃん Advent Calendar 2015 6日目の記事です。qiita.com

シェーダーでアニメ風が出来るなら、コミック風もできるかな。
少し前にそう思って調べたのですが、これだ!というのがありませんでした。
明るいところは白く、暗い部分はスクリーントーンみたいになってくれるといいのですが。

手書き風シェーダーはあるんですが、コミックとは違う。
https://www.assetstore.unity3d.com/jp/#!/content/40360
https://www.assetstore.unity3d.com/jp/#!/content/12465

色々調べていたところ、スクリーントーンのような表現は「ディザリング」というキーワードで探すといいことがわかりました。
そして以下ブログで素敵なシェーダーのソースが公開されていました。wonderpla.net

これをプロ生ちゃんに適用すると、こんな感じ。
f:id:onoty3d:20151204135249p:plain
※テクスチャはアニメ風の時とおなじく、グラデーションなどは付けずベタ塗りにしているものを利用しています。
※また、目のハイライトのみ、Unlit/Transparent Cutoutを利用しています。
※Dither Matrixにbayer.pngを指定するのを忘れずに。

これにアウトライン描画の処理を追加すれば、コミック風になりそうです。

また、陰影の強さは外部のライトの光の強さで調整できますが、これだと全体的にしか調整できません。
特定パーツだけ濃くしたい・薄くしたい、といった場合はテクスチャを直接いじるしかないのですが、それは面倒なのでMain Colorというパラメータも追加し、個別でテクスチャの色味調整が出来るようにしました。

ソース
元ソースに色味の調整を追加

Shader "Custom/OrderedDitheringEX" {
	Properties{
		_Color("Main Color", Color) = (0.5,0.5,0.5,1) //★追加
		_MainTex("Base (RGB)", 2D) = "white" {}
		_MatrixWidth("Dither Matrix Width/Height", int) = 4
		_MatrixTex("Dither Matrix", 2D) = "black" {}
	}

	SubShader{
		Tags{ "RenderType" = "Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Lambert vertex:vert finalcolor:mycolor

		float4 _Color; //★追加
		sampler2D _MainTex;
		int _MatrixWidth;
		sampler2D _MatrixTex;

		struct Input {
			float2 uv_MainTex;
			float4 scrPos;
		};

		void vert(inout appdata_full v, out Input o) {
			UNITY_INITIALIZE_OUTPUT(Input,o);
			float4 pos = mul(UNITY_MATRIX_MVP, v.vertex);
			o.scrPos = ComputeScreenPos(pos);
		}

		void surf(Input IN, inout SurfaceOutput o) {
			half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;  //★修正
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}

		void mycolor(Input IN, SurfaceOutput o, inout fixed4 color) {
			// RGB -> HSV 変換
			float value = max(color.r, max(color.g, color.b));

			// スクリーン平面に対してマトリックステクスチャを敷き詰める
			float2 uv_MatrixTex = IN.scrPos.xy / IN.scrPos.w * _ScreenParams.xy / _MatrixWidth;

			float threshold = tex2D(_MatrixTex, uv_MatrixTex).r;
			fixed3 binary = ceil(value - threshold);
			color.rgb = binary;
			color.a = 1.0f;
		}
		ENDCG
	}
		FallBack "Diffuse"
}

色味の調整+アウトライン処理の追加

Shader "Custom/OrderedDitheringEX Outline" {
	Properties{
		_Color("Main Color", Color) = (0.5,0.5,0.5,1)
		_MainTex("Base (RGB)", 2D) = "white" {}
		_MatrixWidth("Dither Matrix Width/Height", int) = 4
		_MatrixTex("Dither Matrix", 2D) = "black" {}
		_OutlineColor("Outline Color", Color) = (0,0,0,1)
		_Outline("Outline width", Range(.001, 0.03)) = .005
	}

	SubShader{
		Tags{ "RenderType" = "Opaque" }
		UsePass "Toon/Basic Outline/OUTLINE"
		UsePass "Custom/OrderedDitheringEX/FORWARD"
	}
	
	FallBack "Custom/OrderedDitheringEX"
}

※Toon/Basic OutlineシェーダーのOutline描画処理を参照しているため、利用する場合はプロジェクトにToon/Basic Outlineを含めてください。

適用後
f:id:onoty3d:20151204140530p:plain

Outlineの調整で線を細く/太く
f:id:onoty3d:20151204140545p:plain
Main Colorの調整で特定パーツの色を濃く/薄く
f:id:onoty3d:20151204140552p:plain

色々調整して楽しんでみてください。

白枠が描画されるシェーダーを作ってみる

先日ネットをウロウロしている時に、この動画に出会いました。

セルルックなミク動画ですが、ミクを囲む白枠がパネルやシール感を演出し、より2Dっぽく見せています。

MMDに関しては無知なので、この動画ではどのようにこの演出をしているかは不明ですが、Unityの場合はステンシルバッファを利用したマスキングで上手く表現できるのでは、と思いShaderを作成してみました。

ToonOuterFrameShader
(最後にソースも表示)
なお、浅学なためShaderの記述は無駄や間違いがあるかもしれません。ご注意ください…。

ベースは「Toon/Basic Outline」及び「Toon/Lit」シェーダになります。
これらに手を加え、Outlineの外に更に白枠、さらにダミーで影を描画出来るようにしました。通常の外部ライトによる影はモデルそのものの影しか描画されませんが、本件では白枠を含んだ形のままの影が出ないとパネル感が薄れるため、Shader内でダミーの影を描画しています。

公開したUnityPackageをインポートするとOnoty3D/Shaders配下に以下4つのShaderが取り込まれます。Shader名としては"Onoty3D/Toon/~"といった名前になります。

1. ToonLit : Toon/Litにステンシルバッファへの書き込みを追記したもの
2. ToonLitOutline : Toon/Lit Outlineにステンシルバッファへの書き込みを追記、Outlineの描画はToon/Basic Outlineから移植(UsePassせずにToon/Basic Outlineへの依存を切り離し)
3. ToonLitOuterFrame : 1.にステンシルテストおよびバッファへの書き込みと、白枠/影描画処理を足したもの
4. ToonLitOutlineOuterFrame : 1. 2. 3.の合体

白枠を描画させる場合は3.か4.をご利用ください。
4.を利用したマテリアルを適用すると、以下の感じになります。

適用前
f:id:onoty3d:20151202131859p:plain

適用後
f:id:onoty3d:20151202131930p:plain
※Toon Shaderは内部で影を描画するので、メッシュのReceive Shadowsはチェックをはずした方がいいです。また、ダミーな影を落とすので、Cast ShadowsもOffにしていたほうがいいです。

白枠や影はOutlineと同じ理屈で描画した場合、複数オブジェクトを配置したりすると白枠や影が別のオブジェクトに重なってしまうので、ステンシルバッファを利用して外枠だけが描画されるようにしました。

Outlineと同じ理屈で描画した場合
f:id:onoty3d:20151202132023p:plain

ステンシルバッファ利用(Outlineは他オブジェクト上でも描画されるが、枠と影は描画されない)
f:id:onoty3d:20151202132054p:plain
※後述のパラメータ(ステンシルのリファレンス値)の設定次第で、あえて重ねる事もできます。

弱点としては、Toon/Basic Outlineと同じ方法で枠を太らせているので、平面が鋭角で交差するようなオブジェクトに適用すると線が途切れて残念な感じになります。とりあえずこれはこのまま。
f:id:onoty3d:20151202132403p:plain
参考:Unity のトゥーンシェーダについて調べてみた - 凹みTips

 

以下パラメータ説明

f:id:onoty3d:20151202132558p:plain

標準のToon/Basic Outline、Toon/Litにあるパラメータ以外だけ説明します。

Cull Mode
描画のCullingのモードです。0/1/2 = OFF/FRONT/BACKとなっています。
【2015/12/14 追記】選択肢にする方法を覚えたので、最新版ではスライダーからドロップダウンに変わりました。

f:id:onoty3d:20151214200945p:plain

Stcl Ref Main/Outer Frame/Shadow
ステンシルのリファレンス値です。Mainがモデルそのものの描画、Outer Frameが外枠、Outer Shadowがその影の値です。
バッファの値よりリファレンス値が大きかった場合に描画を行います。
Main>Outer Frame>Outer Shadowになるような数値であればなんでもいいです。
他のShaderと干渉するような場合に数値を変えてみてください。

Outer Frame Color/Width
外枠の色と太さです。白枠以外にも、好きな色に変更できます。

Outer Shadow Color/Offset
影の色と位置です。位置はX,Y以外は数値を指定しても意味はありません。

プロ生ちゃんに適用すると、こんな具合になります。

f:id:onoty3d:20151202132651p:plain

f:id:onoty3d:20151202132659g:plain