20190318のUnityに関する記事は3件です。

RenderTexture(Texture2D)を画像保存すると暗い時

概要

D1TflLAVAAACF5T.jpg
© Unity Technologies Japan/UCL
下記のようなスクリプトで画像を保存すると全体的に暗い画像が保存される場合があります。この場合の原因と対策を書きます。

RenderTexture CamTex;

Texture2D tex = new Texture2D(CamTex.width, CamTex.height, TextureFormat.RGB24, false);
RenderTexture.active = CamTex;
tex.ReadPixels(new Rect(0, 0, CamTex.width, CamTex.height), 0, 0);
tex.Apply();

byte[] bytes = tex.EncodeToPNG();
File.WriteAllBytes("RenderTexture.png", bytes);

原因

Edit > Project Settings > PlayerのPlayer SettingsからOther Settings > RenderingよりColor SpaceをLinearに設定している場合に暗くなります。UTS2.0などのシェーダーに関するスライドを読むと、最初に設定するように書かれていることが多い内容です。仕組みが分かると「まぁ、そうか」という感じですが、「原因」として書くようなことではなく、完全に仕様です。

対策1

RenderTexture CamTex;

Texture2D tex = new Texture2D(CamTex.width, CamTex.height, TextureFormat.RGB24, false);
RenderTexture.active = CamTex;
tex.ReadPixels(new Rect(0, 0, CamTex.width, CamTex.height), 0, 0);
/////////////////////////////////////////////////////////////////////////////////////////追加ここから
if (PlayerSettings.colorSpace == ColorSpace.Linear)
{
    // ガンマ補正
    var color = tex.GetPixels();
    for (int i = 0; i < color.Length; i++)
    {
        color[i].r = Mathf.Pow(color[i].r, 1 / 2.2);
        color[i].g = Mathf.Pow(color[i].g, 1 / 2.2);
        color[i].b = Mathf.Pow(color[i].b, 1 / 2.2);
    }
    tex.SetPixels(color);
}
/////////////////////////////////////////////////////////////////////////////////////////追加ここまで
tex.Apply();

byte[] bytes = tex.EncodeToPNG();
File.WriteAllBytes("RenderTexture.png", bytes);

方法は色々ありそうですし、上記があまり良い方法とも思えませんが、とにかくガンマ補正というのをすると解決します。この対策では厳密にはColor SpaceがGammaの時と完全に同じRGB値にならないかもしれませんが、誤差だと思うので気にしないことにします。

※コメントにてご教授頂きましたので、以下加筆します。

対策2

対策1のRGB各色計算を以下のように書き換えます。恐らくですが、こちらの方が正確な値になると思われます。

color[i].r = Mathf.LinearToGammaSpace(color[i].r);
color[i].g = Mathf.LinearToGammaSpace(color[i].g);
color[i].b = Mathf.LinearToGammaSpace(color[i].b);

対策3

これが最も簡単でスマートな方法だと思われますが、以下のように作成したRenderTextureのsRGB設定をチェックありにします。すると、対策1でスクリプトを追加した部分は不要になり、この設定だけで解決します。
無題.png

結果

どの対策も目視では、ほぼ同様の結果になります。
D1UMXVrVsAA-Gpy.jpg
© Unity Technologies Japan/UCL

仕組み

恐らく散々語られてる分野だと思われますので、私が下手な事言うより、検索した方が良いと思います。キーワードは「ガンマ補正」「トーンカーブ」踏み込むと「sRGB」「比視感度」などだと思います。

参考

リニアのワークフローとガンマのワークフロー
https://docs.unity3d.com/ja/current/Manual/LinearRendering-LinearOrGammaWorkflow.html
ガンマ補正
http://w3.kcua.ac.jp/~fujiwara/infosci/gamma.html
明るさの調整(γ補正)
http://www.mis.med.akita-u.ac.jp/~kata/image/colorgamma.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityEditor拡張(入門)自分が最初にしたこと

■最初にやったこと

とりあえず参考になりそうなサイトを読みまくって自分なりにまとめたテキストを作成した。

※一部抜粋

〇標準で使えるエディタ拡張機能
  1.インスペクターの見た目を変える
     ・Range
       int,float,long,doubleなどの数値をスライダーで変更できるようにする機能
      例)
      [Range(1, 10)]
      public int num1;

~以下略~

のような感じで自分なりに解釈した単語帳みたいなものを作成すると覚えも早いと思います。

■実際に作ってみる

まとめたら、まとめたものを中心に一度unityを起動して作ってみる。

〇まずはウィンドウを出してみた

using UnityEngine;
using UnityEditor;//エディタ拡張するときは必ず必要

//EditorWindowクラスを継承
public class StageEditorWindow : EditorWindow 
{
    private const float WINDOWSIZE_W = 500.0f;          //ウィンドウサイズ横幅
    private const float WINDOWSIZE_H = 200.0f;          //ウィンドウサイズ縦幅

    /// <summary>
    /// ウィンドウ表示
    /// </summary>
    [MenuItem("Window/StageEditor")]
    static void Open()
    {       
        var window = GetWindow<StageEditorWindow>();
        //ウィンドウサイズ設定(minとmaxを=しているのはウィンドウサイズを固定するため)
        window.maxSize = window.minSize = new Vector2(WINDOWSIZE_W,WINDOWSIZE_H);
    }
}

エディタ拡張をする際は、継承もとをMonoBehaviourではなくEditorWindowにする。

0318Qiita.png
図1)

[MenuItem("Window/StageEditor")]はメソッドの上に記述することでUnityのエディタ上からこのメソッドを呼び出すことができる。

〇初めて作ったエディタ拡張
いま作っているゲーム用のステージエディタです。(イメージしやすいように…)
0318Qiita.gif
図2)
ステージの名前(保存ファイル名)とステージの横幅を指定して、ステージ上に置くオブジェクトと床のテクスチャをクリックで配置するステージエディタです。

■終わり

今回は、初めてなのでウィンドウ出すだけでしたが次回は実際にボタンとかのレイアウトについて書こうと思います。

お疲れさまでしたm(__)m

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

低コストでVTuberになるために 2 Unityで動かす

はじめに

 それでは本命といえるUnity上で実際に動くようにしていきたいと思います。こまめにセーブしていきましょう。
 モーションキャプチャーについては取り扱いません。そのうち興味が出てやるようなことがあればまた書きますが現時点では自分で調べてがんばってください。(どうやらkinect2出るらしいけどやるかどうかはわかんない。)

 では入れる必要がある(と思われる)アセットを紹介していきます。

UniVRM
 VRM方式のものをUnityで扱うためのアセット。必須。これを書いている時のバージョンは0.51.0。
https://github.com/dwango/UniVRM/releases

OVRLipSync
 声に合わせて唇を動かすためのアセット。
https://developer.oculus.com/downloads/package/oculus-lipsync-unity/

VRMLipSyncContextMorphTarget.cs
 OVRLipSyncをVRMのBlendshapeに対応させるためのスクリプト。これだけは.unitypackegeではないのでスクリプトを直接入れてやります。作者はこちらです→http://teruaki-tsubokura.com/
https://github.com/TsubokuLab/VRMLipSyncContextMorphTarget

kumaS_Assets
 僕が作ったアセット。いろいろ入っている。
https://github.com/kumachan0210/VTuber_env_package

これらをAssets → Import Package → Custom Package...から入れます。

2019-03-13.png

身体を召喚

 モデルのインポートをしていきます。
 VRM → uniVRM-〇.〇〇.〇 → Importから作ったモデルをインポートします。Blenderでいじる人もマテリアルがはがれてしまうので一度入れます。

2019-03-15 (20).png

 このようにモデル用のフォルダをつくるといいです。複数のバージョン入れてるとどれがどれだったかわからなくなるので。
 入った青い立方体(この青い立方体となったやつをprefabといいます。)をhierarchyに置いてやりましょう。

 これで身体が置けました。
 このままだと後姿を映すこととなるのでMain CameraTransformPositionY1.2に、X4.1に、RotationY180に、Field of View27に設定します。

 さらに再生画面の解像度設定をします。デフォルトのままでもいいですができるところまで画質を上げたいでしょう?

 Gameタブを押してその下の左から二番目のところをクリックして開きます。そして+を押して解像度を追加します。

  • Labelに名前を。
  • TypeFixed Resolutionに。

 Width & Heightは解像度を入れます。

  • FHD1920, 1080
  • 4K3840, 2160です。

 それでは再生ボタンを押して動かしましょう。

2019-03-13 (2).png

 …しかし動きません。しかも空中に浮いてて色々おかしいです。(ついでに後ろ髪も見えない…)

部屋を作る

 なんならゲームの世界を作ってもいいのですが簡単に。

 先ほどと同じようにkumaS Assets のObjectsの中のPrefabsにあるBaked Mesh Floorhierarchyに配置します。これで床ができました。
 Baked Mesh Wallを同じように配置すると壁ができます。さらにShellも配置します。これだけです。

 まあ僕が完成品を渡しているだけなんですけど…。なので作り方のほうも説明します

 Hierarchy内で右クリック→3D Object → Planeで板が生成されます。

2019-03-13 (4).png

 そしてお絵かきソフト(僕はめんどくさいので3Dペイントを使ってます)で作ったファイル(.jpegが多いかな)を取り込みます。
 Project内で右クリック→Import New Assets からファイルを選択すれば取り込めます。これ最初にやったAssetタブのやつと同じなのでどっち使ってもいいです。ただしこちらは指定の場所にインポートできる。
 
 取り込んだ絵をさっき作ったPlaneにD&Dすれば完成。
 位置とか角度はがんばって探してね。

動くようにする

 面倒です
 あ、すいません。本音出ました。
 いや、実を言うと最低限動かすのは楽なんですけど僕が追加で作ったやつの設定が割と面倒です。ただ、これがあるのとないのとでは大違いなのでつけるのを推奨します。(といってもこの中の面倒なので。開発と比べたら無視できるレベルですけど。)

最低限動くようにする

2019-03-13 (6).png

 このようにD&Dでくっつけてやります。ここには書けなかったけどVRM→UniVRM→Scripts→BlendShape→Blinkerをアバターにくっつけてやるとまばたきするようになります。

 そしてそれぞれの設定は以下の通りです。

  • RigidbodyConstraintsFreeze RotationX,Zにチェックを入れる。これをしないと倒れます。
  • Capsule Colliderの値をこんな感じにします。この円柱で接触判定をとる。
  • Humanoid Co(ry これはべつにいじらなくてもいい。適度に歩くスピードとかを調整してやるといいです。
  • About Random 待機姿勢と表情のランダムな遷移termが待機姿勢。数字が大きいほど間が長くなる。

 首と頭につけたやつはこっち。

 これと同じように設定がんばってください。首も頭も同じ設定です。それぞれコードのほうにコメントで説明してあるけどこっちでも簡単に説明を。

  • Anim_name 自由に動かしていいアニメーション状態を指定。
  • Key_name どのキーで動かす/動かさないの切り替えをするか。
  • Start 始まりの時に自由に動かせる状態で始まるか否か。
  • Set_start_rot 初めの時のRotation。…ぶっちゃけ作らなくてもよかった。
  • Max それぞれの軸の動かしていい範囲の最大値。
  • Min それぞれの軸の動かしていい範囲の最小値。

 
 ついでに髪が中途半端に見えないのを解消しましょう。

 このようにcull modeOffにするとちゃんと見えるようになります。

 これで最小限動くようになりました。使い方は、

  • 前後左右移動はWASD矢印で。
  • マウス移動で頭が動く。
  • Key_nameで設定したキーで動く/動かない切り替え。
  • Rで正面を見直す。
  • 左Alt + Key_nameで頭の向く方向をそこで固定/解除。
  • (テンキーではないほうの)数字キーでそれぞれアニメーション再生。    

といったところです。動かしてみましょう。

 動きましたね。だけど物足りない。
(ここでカクカクしたり服が貫通したりするのはスペック不足です。後のほうに軽量化の方法を書きますのでそこまで我慢してください。…本当にスペックが足りなかったらごめんなさい。)

十分に動かせるようにする

 それでなにをするのか。目が動くようにする&腕を動くようにする&リップシンク。
 それぞれのスクリプトをこのようにアタッチします。

 そしてそれぞれの設定はこのようになります。

 

  • Anim 参照するAnimator。図のようにD&Dすればいい。
  • Anim_name 動いていいアニメーションの状態
  • Key_name 動かす/動かさないの切り替えのキー
  • Start 始まったときに動かせるかどうか
  • Set_start_rot 初めの時のRotation。…ぶっちゃけ作らなくてもよかった。
  • Max それぞれの軸の動かしていい範囲の最大値。
  • Min それぞれの軸の動かしていい範囲の最小値。
  • Cam_obj カメラ。Main CameraをD&Dすればいい。
  • L_r 右目か左目か。

 
 左腕

 右腕

  • Anim 参照するAnimator。図のようにD&Dすればいい。
  • Anim_name 動いていいアニメーションの状態
  • Key_name 動かす/動かさないの切り替えのキー
  • Start 始まったときに動かせるかどうか
  • Set_start_rot 初めの時のRotation。…ぶっちゃけ作らなくてもよかった。
  • Max それぞれの軸の動かしていい範囲の最大値。
  • Min それぞれの軸の動かしていい範囲の最小値。
  • L_r 右腕か左腕か。
  • Sec_key SHIFT押しながら切り替えるやつかどうか。

 そしてリップシンクはhierarcheyで右クリック、Create Emptyで空のゲームオブジェクトを作ってこうします。

2019-03-15 (11).png

 これでリップシンクができるようになったはずです。

 もう一度動かしてみましょう。操作方法は先ほどとほぼ変わらないです。追加要素としては、

  • Shift + 1で常にカメラ目線となります。Shift + 0で自由に目を動かせるようになります。
  • 腕はホイールの操作でも動きます。

色の調整

 今更なんですが、VRoidでの色とUnity上での色となんか違うという人がいるかもしれません。
 その原因は太陽光にあたるものMToonの設定がずれているかの二択です。

 太陽光にあたるものはDirectional Lightといいます。ここで設定を変える必要があるのは、ColorIntensityです。それぞれ意味はそのままです。わからなかったら辞書を引いてください。
 ただ、僕は軽量化のために無効化したのでこっちの設定はスペックに余裕のある人向け。(スペックに余裕があるかどうか調べるのは次に書きます。)

軽量化

 でき上ったものなのですが、それなりに重いです。
 どれぐらい重いか調べるにはWindow → Analysis → Profilerをクリックし、さらにAdd ProfilerでGPUを選択します。その状態で再生すると処理にどれだけ時間がかかっているか表示してくれます。

2019-03-15 (14).png

 見てもらうとわかる通りOpaque, Shadows/depth, Renderingが重めです。ということでこれらを軽くしていきます。

 これらは一体何か。それは光です。(詳しくは違います。雑でごめんなさい)ということでDirectional lightを無効化してやります。
 チェックを外してやるだけ。

 …。床とか壁とかは大丈夫ですが、アバターが真っ黒になっちゃいました。考えてみれば当然で光が無ければ暗くなります。
 じゃあなぜ床とか壁とか大丈夫なのか。実はこれらは光を発するように僕が設定していたからなんですよね。ということでそのやり方を説明していきます。

 まず、設定を変える必要があるのはここにあります。(青で囲ってあるところ)
2019-03-15 (16).png

 そして実際に変える画面はここ。
2019-03-15 (17).png

 青で囲ったところを押してその中から赤で囲ったところにあるやつと同じものを探し出します。そしてその隣のHDRと書かれているところをクリックし、RGBそれぞれ195ぐらいにして、Intensityを0.5前後で調整する(中には色がおかしくなるやつがあるのでそれは目指している色に設定)とよくなります。

それではどれぐらい軽量化されたか見ていきましょう。



多少軽くなりました。

最後に

これで動くものができました。あと最後に一仕事。このままじゃ使えないので。

2019-03-15 (18).png

FileBuild Settings... をクリックする。

2019-03-15 (19).png

Target Platformが間違っていないことを確認しBuildを押す。これで.exeファイルとして出力されます。

 お疲れさまでした。次はBlenderでアニメーションを作るです。

おまけ

 僕はやらないのですが配信をするためOBS等を使うから背景をとある色にしたいという場合があると思います。そのときは背景を消してMain CameraClear FragsSolid Colorにして、Background目的の色にしてやるとできます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む