読者です 読者をやめる 読者になる 読者になる

Onoty3D

Unityに関するメモとか

Shaderでゾワゾワ表現

Unity Shader プロ生ちゃん

ふと、アニメなんかでみるゾワゾワッとする表現がShaderで作ってみたくなったので試してみました。
まだ課題が残っていますがとりあえず一旦ここで一息。

結果から出すとこんな感じになりました。
f:id:onoty3d:20161109185553g:plain

UnityPackageはこちら
Unity5.5で作成したので、5.4以前で上手く動かないかもしれません。
ToonLit Shaderがベースなので、各バージョンのToonLit Shaderにパラメータと数式を移植すれば動くと思います。

またテッセレーションが有効な環境(DX11以上 / OpenGL Core)でないと動きません。

使い方

Shaderのパラメータはこんな感じ。
パラメータ名は雰囲気で付けました。
f:id:onoty3d:20161109190148p:plain
YBorder:ゾワゾワっとさせる中心となるY座標です。Materialをセットするメッシュでのローカル座標になります。

※ここを動かすとゾワゾワ位置が移動します。
上記動画はスクリプトでこのYBorderを変化させています。なのでShaderだけでゾワゾワが下から上に走るわけではありません。
あしからず。

YRange:YBorder±YRangeの範囲をゾワゾワっとさせます。
Volume:ゾワゾワの大きさです。
Pow:後述のGapを顕著にします
Gap:ゾワゾワの高低差を大きくします
Fineness:ゾワゾワの細かさです。
Edge:ゾワゾワを出す頂点とカメラの向きの関係です。0に近いほどカメラに対して横を向いている頂点(基本的にモデルの端っこ)からゾワゾワがでます。
Tessellationテッセレーションのパラメータ

とりあえず、適当に色々触ると色々動くので試してみてください。
f:id:onoty3d:20161109191625g:plain

うまくやればFur Shaderっぽくもなります。
f:id:onoty3d:20161109194744p:plain

メモ

はじめは単純に頂点を動かすだけだったんですが、ボコボコとした三角形が出来るだけでした。
f:id:onoty3d:20161109190612g:plain
この時点でもっとハイポリゴンなメッシュじゃないと無理かな、と思ってやめようと思ったのですが、
Twitterテッセレーション使いなされとアドバイスを貰ったのでテッセレーション処理も入れてみるとうまく行きました。
とりあえず固定量のテッセレーション

課題

球体など完全に凸なメッシュの場合はEdgeを0近くにすれば端からしかゾワゾワは出ませんが、凹凸のあるメッシュの場合は意図せぬ部分からもゾワゾワが出ます。
例えばプロ生ちゃんの髪だと、前髪からも出ます。
f:id:onoty3d:20161109190934p:plain
ステンシルバッファを使ってマスク処理するとか、Z座標の位置も判定に入れるとか、そのへんで調整すればいいかもしれません。

ソース

Shader "Onoty3D/Toon/Lit ZowaZowa" {
	Properties{
		_Color("Main Color", Color) = (0.5,0.5,0.5,1)
		_MainTex("Base (RGB)", 2D) = "white" {}
		_Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
		[Enum(OFF,0,FRONT,1,BACK,2)] _CullMode("Cull Mode", int) = 2 //OFF/FRONT/BACK
		
		_YBorder("YBorder", float) = 0
		_YRange("YRange", float) = 0.005
		_Volume("Volume", float) = 0.001
		_Pow("Pow", Range(0, 3)) = 2
		_Gap("Gap", Range(1, 3)) = 2
		_Fineness("Fineness", float) = 12
		_Edge("Edge", Range(0, 1)) = 0.1
		_Tess("Tessellation", Range(1, 32)) = 4
	}

		SubShader{
		Tags{ "RenderType" = "Opaque" }
		LOD 200
		Cull[_CullMode]

		CGPROGRAM
#pragma surface surf ToonRamp vertex:vert tessellate:tessFixed
#pragma target 5.0
			sampler2D _Ramp;

#pragma lighting ToonRamp exclude_path:prepass
			inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
			{
#ifndef USING_DIRECTIONAL_LIGHT
				lightDir = normalize(lightDir);
#endif

				half d = dot(s.Normal, lightDir) * 0.5 + 0.5;
				half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;

				half4 c;
				c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
				c.a = 0;
				return c;
			}

			float _Tess;
			float4 tessFixed()
			{
				return _Tess;
			}

			struct Input {
				float2 uv_MainTex : TEXCOORD0;
			};

			float _YBorder;
			float _YRange;
			float _Volume;
			float _Gap;
			float _Pow;
			float _Fineness;
			float _Edge;

			void vert(inout appdata_full v) {
				float4x4 modelMatrix = unity_ObjectToWorld;
				float4x4 modelMatrixInverse = unity_WorldToObject;

				float3 normalDirection = normalize(mul(v.normal, modelMatrixInverse)).xyz;
				float3 viewDirection = normalize(_WorldSpaceCameraPos - mul(modelMatrix, v.vertex).xyz);

				float dotValue = saturate(dot(normalDirection, viewDirection));
				float fineness = _Fineness * 100;

				if (dotValue < _Edge) {
					if (abs(v.vertex.y - _YBorder) < _YRange) {
						//ゾワゾワを表現する部分はとりあえずいろいろ試して個人的にいい感じになった数式で特に思想があるわけではありません。
						//float3 value = v.normal * _Volume * pow(_Gap * (sin(v.vertex.y * _Fineness) + sin(v.vertex.x * _Fineness) + sin(v.vertex.z * _Fineness)), _Pow);
						float3 value = v.normal * _Volume * pow(_Gap * (sin(v.normal.y * fineness) + sin(v.normal.x * fineness) + sin(v.normal.z * fineness)), _Pow);
						v.vertex.x += value.x;
						v.vertex.y += value.y;
						v.vertex.z += value.z;
					}
				}
			}

			sampler2D _MainTex;
			float4 _Color;

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

	}

	Fallback "Diffuse"
}

メッシュの頂点を動かして、プロ生ちゃんの舌を操作する

Unity スクリプト プロ生ちゃん

プロ生ちゃんの舌をスクリプトで動かせるようにしてみました。


舌ネタは以前にもやりました。
onoty3d.hatenablog.com
この投稿では、ニコニ立体ちゃんの舌を拝借してプロ生ちゃんに舌を足しました。
また、以下の投稿で公開したスクリプトを使えば、ニコニ立体ちゃんの舌でなくても、プロ生ちゃん自身の舌を切り出して利用することができます。
onoty3d.hatenablog.com

しかし今回はメッシュの舌部分の頂点を移動させることで制御してみました。
(はじめはシェーダでの擬似的な頂点移動も考えましたが、その場合自分が使いたいシェーダ毎に実装する必要があるため面倒になった。)

Unity Editor上で表情なんかを楽しむ分には問題ないはずです。
UnityPackageはこちら。(ソースは末尾。)

TongueMorph

使い方

UnityPackageを任意のプロジェクトにインポートしたら、追加されるTongueMorphというスクリプトをプロ生ちゃんにセットしてください。
セットすると、インスペクタ上の表示はこのようになります。
f:id:onoty3d:20161021135110p:plain

TongueIndex

セットするモデルによって変更してください。
ノーマルモデル:21
Tシャツモデル:17
SDモデル:19
TongueIndexの値を間違うと、エラーになったり他の部位が動いたりするので気をつけてください。
なお実行中に値を変更しても効果はありません。

SkinnedMeshRenderer

プロ生ちゃんのSkinnedMeshRendererです。
基本的には実行時に勝手に見つけてきますが、プロ生ちゃん内部に他にSkinnedMeshRendererを持つオブジェクトを持たせたりしている場合は、手動で正しいSkinnedMeshRendererをセットしておいてください。

Width,MoveForward,MoveUp

Width:舌の幅を調整します。
MoveForward:舌を前方に移動させます。
MoveUp:舌を上方に移動させます。
f:id:onoty3d:20161021135209g:plain

VertucalRotationCenter,VertucalRotation

VertucalRotation:舌を縦方向に回転させます。
VertucalRotationCenter:縦方向回転の中心を移動させます。中心より先の部分だけが回転します。
0が舌の根元、1が舌の先端になります。
f:id:onoty3d:20161021135419g:plain

HorizontalRotation,Inclination

HorizontalRotation:舌を水平方向に回転させます。
Inclination:舌を傾斜させます。
f:id:onoty3d:20161021135457g:plain

以上を組み合わせて、いろいろな表情を作ってみてください。
f:id:onoty3d:20161021135553p:plain

ソース

using System.Linq;
using UnityEngine;

namespace PronamaChan
{
    public class TongueMorph : MonoBehaviour
    {
        private class DefaultVertex
        {
            public int Index { get; set; }

            public Vector3 Vertex { get; set; }
        }

        public SkinnedMeshRenderer SkinnedMeshRenderer;

        public float Width = 1;

        //前後移動
        [Range(0, 4)]
        public float MoveForward = 0;

        //上下移動
        [Range(0, 2)]
        public float MoveUp = 0;

        //縦回転中心
        [Range(0, 1)]
        public float VerticalRotationCenter = 0.5f;

        //縦回転
        [Range(-90, 90)]
        public float VerticalRotation = 0;

        //横回転
        [Range(-90, 90)]
        public float HorizontalRotation = 0;

        //傾き
        [Range(-90, 90)]
        public float Inclination = 0;

        public int TongueIndex;

        private Vector3 _rotationCenter;

        private float _verticalRotationCenterZero;
        private float _verticalRotationCenterVolume;

        private Mesh _mesh;

        private DefaultVertex[] _defaultTongueVertices;

        // Use this for initialization
        private void Start()
        {
            //SkinnedMeshRendererの取得
            if (this.SkinnedMeshRenderer == null)
            {
                this.SkinnedMeshRenderer = this.GetComponentInChildren<SkinnedMeshRenderer>();
            }

            //メッシュのクローンをSkinnedMeshRendererにセット
            this._mesh = this.SkinnedMeshRenderer.sharedMesh;
            this._mesh = GameObject.Instantiate(this._mesh);
            this._mesh.MarkDynamic();
            this.SkinnedMeshRenderer.sharedMesh = this._mesh;

            //舌のサブメッシュのインデックスリスト取得
            var triangles = this._mesh.GetTriangles(this.TongueIndex);
            var trianglesUnique = triangles.Distinct().ToArray();

            //舌の頂点位置保存
            this._defaultTongueVertices = trianglesUnique.Select(x => new DefaultVertex { Index = x, Vertex = this._mesh.vertices[x] }).ToArray();

            //回転中心の決定
            var minMax = _defaultTongueVertices.Select(x => new { MinY = x.Vertex.y, MaxY = x.Vertex.y, MinZ = x.Vertex.z, MaxZ = x.Vertex.z })
                .Aggregate((x, y) => new { MinY = Mathf.Min(x.MinY, y.MinY), MaxY = Mathf.Max(x.MaxY, y.MaxY), MinZ = Mathf.Min(x.MinZ, y.MinZ), MaxZ = Mathf.Max(x.MaxZ, y.MaxZ) });
            this._rotationCenter = new Vector3(0, 0, (minMax.MinZ + minMax.MaxZ) / 2f);
            this._verticalRotationCenterZero = minMax.MaxY;
            this._verticalRotationCenterVolume = minMax.MaxY - minMax.MinY;
        }

        // Update is called once per frame
        private void Update()
        {
        }

        public void OnValidate()
        {
            if (this._defaultTongueVertices == null)
            {
                return;
            }

            //現在の頂点取得
            var vertices = this._mesh.vertices;

            foreach (var defaultVertex in this._defaultTongueVertices)
            {
                var newVertex = defaultVertex.Vertex;

                //舌の幅の変更
                newVertex.x *= this.Width;

                //縦方向回転
                {
                    //回転の中心を舌の根元から任意の位置に移動
                    var rotationCenterVertical = this._rotationCenter;
                    rotationCenterVertical.y = this._verticalRotationCenterZero - this._verticalRotationCenterVolume * this.VerticalRotationCenter;
                    //任意の位置から先だけを回転
                    if (defaultVertex.Vertex.y < rotationCenterVertical.y)
                    {
                        newVertex = Quaternion.Euler(this.VerticalRotation, 0, 0) * (newVertex - rotationCenterVertical) + rotationCenterVertical;
                    }
                }

                //横方向回転・傾き
                newVertex = Quaternion.Euler(0, this.Inclination, this.HorizontalRotation) * (newVertex - this._rotationCenter) + this._rotationCenter;

                //前後上下移動
                newVertex.y += -this.MoveForward / 100.0f;
                newVertex.z += this.MoveUp / 100.0f;

                vertices[defaultVertex.Index] = newVertex;
            }

            this._mesh.vertices = vertices;
            this._mesh.RecalculateNormals();
            this._mesh.RecalculateBounds();
        }
    }
}

ToonLit ShaderにPhong Tessellation機能を追加する。

Unity Shader クエリちゃん

f:id:onoty3d:20161006205756g:plain

Phong Tessellationとはなんぞや?って人はまず公式のリファレンスを見てみてください。

docs.unity3d.com

これをToonShaderで実現するには、既存のコードにリファレンスを参考にPhong Tessellationに必要な記述を移植します。
それだけ~。

…で、終わらせたかったんですが、OutLineが上手くいかなかったんです。
標準のToonShaderではOutLineは頂点とフラグメントシェーダで記述されているんですが、そこで上手く書くやり方がわからぬ。

いろいろ錯誤してみたんですが、全て徒労に終わりました。

ググったら同じように悩んでいる人を発見しましたが、この人は最終的にSurfaceシェーダでアウトラインも書くことで解決していました。

community.unity.com

というわけで自分も同じ感じの実装にしました。
ただし元々のToonLit ShaderのOutLineは透過が可能なので、その機能も追加しています。

Unity5.3-5.4で動きます。

https://dl.dropboxusercontent.com/u/22011827/Unity/TessellationToon.unitypackage

 

ちなみに画像はクエリちゃんです。

クエリちゃん公式サイト

f:id:onoty3d:20161006210504p:plain

 

プロ生ちゃんのスパッツ・靴下・靴以外も切り替えられるようにする

Unity プロ生ちゃん スクリプト

プロ生ちゃん新モデルに含まれているプレハブで
PronamaChan_dynamic_base
という名前のものには、EquipmentsChangerというスクリプトがつけてあります。
このスクリプトは、靴下・靴・スパッツの表示切り替えが出来るスクリプトです。
f:id:onoty3d:20160927195758g:plain

ですが場合によってはもっとスポーティに見える画も作りたかったりするじゃないですか。
こんな。
f:id:onoty3d:20160927200136p:plain
なのでEquipmentsChangerをもう少し改良してスカート・時計の表示切り替えも出来るようにしてみました。
おまけでブルマモードも作ったよ。

ソースこちら。

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace PronamaChan
{
    public class EquipmentsChanger2 : MonoBehaviour
    {
        public Material TransparentMaterial;
        public SkinnedMeshRenderer SkinnedMesh;

        public bool ShowSpats = false;
        public bool ShowSocks = true;
        public bool ShowShoes = true;
        public bool ShowSkirt = true;
        public bool ShowWatch = true;
        public bool ShowBuruma = false;

        [TooltipAttribute("太もも\nすね\nつま先\n靴下すね\n靴下つま先\nパンツ\nスパッツ\n\nスカート\nスカート裏\n時計\nの順でMaterialのIndexをセット")]
        public int[] MaterialIndexes = new[] { 1, 3, 2, 10, 9, 0, 5, 8, 11, 12, 26 };

        private Dictionary<MaterialIndexesKey, Material> _materialsDic;

        private enum MaterialIndexesKey
        {
            /// <summary>太もも</summary>
            Thigh,

            /// <summary>すね</summary>
            Shin,

            /// <summary>つま先</summary>
            Toe,

            /// <summary>靴下すね</summary>
            SocksShin,

            /// <summary>靴下つま先</summary>
            SocksToe,

            /// <summary>パンツ</summary>
            Pants,

            /// <summary>スパッツ</summary>
            Spats,

            /// <summary></summary>
            Shoes,

            /// <summary>スカート</summary>
            Skirt,

            /// <summary>スカート裏</summary>
            SkirtReverse,

            /// <summary>時計</summary>
            Watch
        }

        // Use this for initialization
        private void Start()
        {
            this.StoreMaterials();
            this.ChangeEquipments();
        }

        // Update is called once per frame
        private void Update()
        {
        }

        private void StoreMaterials()
        {
            this._materialsDic = new Dictionary<MaterialIndexesKey, Material>();
            var materials = this.SkinnedMesh.sharedMaterials;

            foreach (var item in Enum.GetValues(typeof(MaterialIndexesKey)).Cast<MaterialIndexesKey>().Select((x, i) => new { Index = i, Key = x }))
            {
                this._materialsDic[item.Key] = materials[this.MaterialIndexes[item.Index]];
            }

            //スパッツのRenderQuereを太もものそれより大きくしておく
            this._materialsDic[MaterialIndexesKey.Spats].renderQueue = this._materialsDic[MaterialIndexesKey.Thigh].renderQueue + 1;
        }

        private void OnValidate()
        {
            this.ChangeEquipments();
        }

        private void ChangeEquipments()
        {
            if (_materialsDic == null) return;

            var renderer = this.SkinnedMesh.GetComponent<Renderer>();
            var materials = renderer.sharedMaterials;

            if (this.ShowBuruma)
            {
                this.ChangeToOrigin(materials, MaterialIndexesKey.Pants);
                this.ChangeToOrigin(materials, MaterialIndexesKey.Thigh);
                this.ChangeToTransparent(materials, MaterialIndexesKey.Spats);

                //パンツのマテリアルをスパッツのものに置き換え
                materials[this.MaterialIndexes[(int)MaterialIndexesKey.Pants]] = this._materialsDic[MaterialIndexesKey.Spats];
            }
            else
            {
                //スパッツのマテリアルをパンツのものに置き換え
                materials[this.MaterialIndexes[(int)MaterialIndexesKey.Spats]] = this._materialsDic[MaterialIndexesKey.Pants];

                //スパッツの表示切り替えが有効なのは、ブルマ非表示の時のみ
                if (this.ShowSpats)
                {
                    this.ChangeToTransparent(materials, MaterialIndexesKey.Pants);
                    this.ChangeToTransparent(materials, MaterialIndexesKey.Thigh);
                    this.ChangeToOrigin(materials, MaterialIndexesKey.Spats);
                }
                else
                {
                    this.ChangeToOrigin(materials, MaterialIndexesKey.Pants);
                    this.ChangeToOrigin(materials, MaterialIndexesKey.Thigh);
                    this.ChangeToTransparent(materials, MaterialIndexesKey.Spats);
                }
            }

            if (this.ShowSocks)
            {
                this.ChangeToTransparent(materials, MaterialIndexesKey.Shin);
                this.ChangeToTransparent(materials, MaterialIndexesKey.Toe);
                this.ChangeToOrigin(materials, MaterialIndexesKey.SocksShin);

                if (this.ShowShoes)
                {
                    this.ChangeToTransparent(materials, MaterialIndexesKey.SocksToe);
                    this.ChangeToOrigin(materials, MaterialIndexesKey.Shoes);
                }
                else
                {
                    this.ChangeToOrigin(materials, MaterialIndexesKey.SocksToe);
                    this.ChangeToTransparent(materials, MaterialIndexesKey.Shoes);
                }
            }
            else
            {
                this.ChangeToOrigin(materials, MaterialIndexesKey.Shin);
                this.ChangeToTransparent(materials, MaterialIndexesKey.SocksShin);
                this.ChangeToTransparent(materials, MaterialIndexesKey.SocksToe);

                if (this.ShowShoes)
                {
                    this.ChangeToTransparent(materials, MaterialIndexesKey.Toe);
                    this.ChangeToOrigin(materials, MaterialIndexesKey.Shoes);
                }
                else
                {
                    this.ChangeToOrigin(materials, MaterialIndexesKey.Toe);
                    this.ChangeToTransparent(materials, MaterialIndexesKey.Shoes);
                }
            }

            if (this.ShowSkirt)
            {
                this.ChangeToOrigin(materials, MaterialIndexesKey.Skirt);
                this.ChangeToOrigin(materials, MaterialIndexesKey.SkirtReverse);
            }
            else
            {
                this.ChangeToTransparent(materials, MaterialIndexesKey.Skirt);
                this.ChangeToTransparent(materials, MaterialIndexesKey.SkirtReverse);
            }

            if (this.ShowWatch)
            {
                this.ChangeToOrigin(materials, MaterialIndexesKey.Watch);
            }
            else
            {
                this.ChangeToTransparent(materials, MaterialIndexesKey.Watch);
            }

            renderer.sharedMaterials = materials;
        }

        /// <summary>
        /// マテリアルを元に戻す
        /// </summary>
        /// <param name="materials"></param>
        /// <param name="key"></param>
        private void ChangeToOrigin(Material[] materials, MaterialIndexesKey key)
        {
            materials[this.MaterialIndexes[(int)key]] = this._materialsDic[key];
        }

        /// <summary>
        /// マテリアルを透過のものに置き換える
        /// </summary>
        /// <param name="materials"></param>
        /// <param name="key"></param>
        private void ChangeToTransparent(Material[] materials, MaterialIndexesKey key)
        {
            materials[this.MaterialIndexes[(int)key]] = this.TransparentMaterial;
        }
    }
}

これをプロ生ちゃんに適用させれば、スカート・時計の表示切り替えとパンツ・スパッツ・ブルマの表示切り替えができるようになります。
マテリアルのインデックスはTシャツモデルのものに併せているので、他モデルでも使いたい場合はEquipmentsChangerの設定値を参考にセットしてみてください。
SDモデルはスカートのマテリアルがひとつなので、同じインデックスを指定すればいいと思います(試してないけど)。
なおブルマ表示モードのときはスパッツ・パンツの切り替えが出来ない仕様になってるのでご注意ください。

プロ生ちゃんのTシャツに絵を重ねてみよう

Unity プロ生ちゃん

プロ生ちゃんの新モデルが公開されています。

pronama.azurewebsites.net

MMD版が先行しておりますが、Unity版も近日中に公開されることと思います。
この記事は、そのUnity版を対象とした内容になります。

さて、新モデルですが、Tシャツモデルが登場しています。

f:id:onoty3d:20160927190154p:plain

デフォルトでは無地の真っ白なTシャツを着ておりますが、マテリアルを調整して色を変えたり、テクスチャを編集したりして任意の柄を付けたりすることが可能です。

テクスチャに手をいれるのは少々手間ですが、デカールシェーダのようなシェーダを利用すれば、元のテクスチャはそのままに、その上に任意の絵を重ねる事ができます。

f:id:onoty3d:20160927185638p:plain

f:id:onoty3d:20160927185702p:plain

また、そのような機能のないシェーダでもかんたんに絵を重ねる方法を見つけたので、今回はその方法を紹介します。

絵を用意する

まずは重ねたい絵を用意し、それをUnityに取り込みます。

f:id:onoty3d:20160927185746p:plain

f:id:onoty3d:20160927185823p:plain
絵のタイプによって背景を透過にする設定を行ったりしてください。
また、WrapModeをClampにすると、絵がリピートすることが無くなります。

マテリアルを作る

絵が用意できたら、それを表示させるマテリアルを作ります。f:id:onoty3d:20160927185846p:plain
背景を透過にする場合は、透過が出来るシェーダーを選んでください。

SkinnedMeshRendererにセットする

マテリアルが出来たら、それをプロ生ちゃんのSkinnedMeshRendererのMaterialsの29番目のマテリアルとしてセットしてください。f:id:onoty3d:20160927185919p:plain
※MaterialsのSizeを29に変更すると、マテリアルの枠が1枠増える(デフォルトで28番目のマテリアルと同じマテリアルがセットされる)ので、そこに作成したマテリアルをセットしてください。

これでTシャツの上に絵が重ねられます。

f:id:onoty3d:20160927190032p:plain

そのままだと位置やサイズがおかしかったりするので、マテリアルのTilingやOffsetを調整して、いい具合にしてみてください。

HoloLens体験してきました。

HoloLens

HoloLens体験会、参加してきました。

hololens.connpass.com


デベロッパー向け開発キットが売り出されてからネット上でちらほら動画等は見ていたのですが、レンズの内側から見た映像はあんまりなかったので、是非とも体験してみたいと思っていたところでした。
HoloLensはsilkyfeelの蜜葉さんが貸してくれました!

f:id:onoty3d:20160604115227j:plain

HoloLens一台での体験会でしたが、体験者が見ている映像は同時にスクリーンにも映しだされていたため、体験者以外の人たちも同時に楽しむことが出来ました。

f:id:onoty3d:20160604120542j:plain

一番気になっていたのは視野の狭さだったのですが、動きの激しいコンテンツなど中心部分に意識が集中しやすいコンテンツだと気にならないと思います。
そうじゃないコンテンツも、表示されているオブジェクトがほとんどぶれないため「この場所にこれがある」という認識が強くなって、見えなくなっても位置が把握できる感じでした。

他に気になっていたのは発色ですが、これも綺麗に出ていました。もう少しお化けみたいな見え方するのかと思っていましたが。

コンテンツは自由な位置に配置できるので、複数のコンテンツを空間に沢山並べることが出来ます。
ただ起動すればするほどごちゃごちゃになるので、自分のような片付けが出来ない人には辛いかも。
すべてを一気に閉じる機能はまだ未実装のようです。
名前を呼んだら該当コンテンツの窓が目の前に移動してきてくれたら楽しいかもしれません。
あとはWin10の仮想デスクトップみたいな機能があれば、もう少し整理できそうですが…あるのかな?

自作アプリを持ってこられた方もいらっしゃいましたが、エミュレータと実機では結構勝手が違うようです。
いま実機を持っている方は相当のアドバンテージになるんだろうな、と思います。
今回自分はなにもアプリを用意できなかったのですが、今後再び体験できる機会があったら、その時は是非ともなにか作って持って行きたいものです。

f:id:onoty3d:20160604115431j:plain
© UTJ/UCL
床に寝そべってユニティちゃんを覗きこむ強者も居ました。

DepthImageEffectにイージング処理を追加してみた。

Unity Image Effect ニパ子ちゃん

以前作成したDepthImageEffect。

onoty3d.hatenablog.com

Depthの値をそのまま濃淡に反映していましたが、イージング処理を加えて濃淡の変化を直線的なものから曲線的なものに変えてみました。

DepthImageEffect

スクリプトをカメラにセットすると、利用可能です。
(今回からマテリアルを自動生成するようにしたので、マテリアルのセットは不要です。)

パラメータとして、新たにEasing ModeとInOutModeを追加しているので、適当に変えてみてください。

f:id:onoty3d:20160531174747p:plain

こんな感じで変化します。

f:id:onoty3d:20160531174605g:plain

イージングの計算式は以下のサイトを参考にしました。
Easing Equations

各処理の視覚的な変化は以下のサイトのほうが分かりやすいかもしれません。
easing_demo

 モデルはニパ子ちゃんです。

www.28ko.jp