Unity

ホラーゲーム作ります:テクスチャ・演出・D言語くん

バイオ7出ました。素晴らしくて泣いた。決して怖くて泣いたのではありません。

せっかくなので試しにホラーゲーム作ってみたい。ホラーゲームも一人称ゲームも作ったことないし。

早速モデル作りました。こんな感じです(Blender内です)
asdfasdf

これどっかで見たような。。って思ったあなた、友達になってください。
(がっこうぐらしですねはい)

でもこれテクスチャがないとあまり怖くないですね。SubstancePainterに移りましょう。(ここから宣伝)

まず古い校舎感を出すために、「Coarse cement」のレイヤーに「Fine cement」をかけて、マスクで削る壁を演出した。さらにその上にほこりを載せる。

Screenshot (683)

おお、いい感じ。(これにはあらかじめ分割したモデルをベースにノーマルなどをベークした(例の椅子のヤツです))

では、ちょっと血を入れます。物理エンジン(?!)が使えるので、HeavyLeakingやBurn効果(Diffuse色やSpecular, Glossinessをいじったもの)を使ってみよう。

血はDiffuse #770000 Specular #ff6666 Glossiness 0.3かな(だいたい)。旧い血痕はSpecular低めで。

particles

グロ。でも好き。

さて、これをUnityにエクスポートしよう。Export Textures押すとUnityのStandard Materialがすぐ使えるDiffuse, Specular, Normal, Height, Occlusionマップが生成される。これを適用してみよう。

普通の照明じゃ面白くないので、カメラについているSpotlightで照らそう。

Screenshot (727)

怖い怖いちょっと待ていい雰囲気じゃねぇか。ほんとのホラーゲームっぽいぞ。(ホラーゲームです)

 

他のアセット:

1.KCSxUnity本

Screenshot (693)

2.D言語くん Screenshot (719)

↑Sketchfabはいいぞ。

この感じでアセットを作ると超便利で速い!

 

(ネタばれしたら実際のプレイも怖くなくなるので、他のシーンのものは見せられません。お楽しみに。)

では。

Unityを拡張しよう!#1: .Blendファイルを使いこなそう!

どうも、チョコです。

Unityで「これやりたい!」って思ったとき、機能不足でできないこと多いよね。拡張(エディタースクリプト)を書けばいいんだけど、そもそもアセットで使えるデータが限られているからできない。。。なんて思ったことあるかな。

今回はBlenderファイルをUnityで開いて、普通じゃ手に入れられない情報を抽出してみよう!

**この文書を読むにはUnity、C#、Pythonと英語(?)の前提知識が必要です。

Blenderを背景で開く

Blendファイルを読み取るためには、ユーザーが(当然ながら)Blenderを持っていないとできないので、まずBlenderの居場所を確認する。Windowsの場合は、RegistryEditorのSOFTWAREMicrosoftWindowsCurrentVersionUninstallキーにあります。

**注意:RegistryEditorをいじる時に注意してください。変なものいじったりしまうとOSが動かなくなる場合があります。

このキーの中にはすべてインストールされたプログラムが入っているので、Blenderのキーの存在を確認します。

screenshot-246

あった。ではここからBlender.exeの場所を出そう。

<br />
using (RegistryKey key = Registry.LocalMachine.OpenSubKey (registry_key)) {<br />
    foreach (string s in key.GetSubKeyNames()) {<br />
        using (RegistryKey key2 = key.OpenSubKey(s)) {<br />
            if ((string)key2.GetValue(&quot;DisplayName&quot;, &quot;&quot;) == &quot;Blender&quot;)<br />
                location = (string)key2.GetValue(&quot;InstallLocation&quot;, &quot;&quot;) + &quot;Blender.exe&quot;;<br />
         //なんかする<br />
        }<br />
    }<br />
}<br />

**細かい説明は省略させていただきます。(レポートまだ書いてないorz

BlenderでPythonスクリプトを実行

Blenderは、アッドオンやTextEditorでPythonスクリプトを実行し、シーン内のデータを編集したりできます。これを活かしてみよう。具体的には、Pythonを実行し、Unityのアセットフォルダになんか書き込もう。

まず、「System.Diagnostics.ProcessでBlenderを起動し、Pythonを実行して、自動で閉じる」のを背景でやってもらおう。Blender APIに書いてある通り–backgroundコマンドを送ります。
fileはアセットの中の.Blendのパス(例えば、F:/MyProject/Assets/Hoge.blend)。
**以下のコードはエディタースクリプトに入れます。やり方省略

<br />
Process.Start (location, file + &quot; &#8211;background&quot;);<br />

これでBlenderは背景起動された。コマンドみたいなものが起動されますね。

では、Pythonスクリプトを実行しよう。まずはこのスクリプトを実行してみよう。

<br />
Process.Start (location, file + &quot; &#8211;background &#8211;python &quot; + Application.dataPath + &quot;/Editor/hoge.py&quot;);<br />

そして、エディターフォルダに以下のhoge.pyを入れよう。

<br />
import bpy<br />
import sys<br />
class Hoge():<br />
 def execute(self):<br />
   print (&quot;hi&quot;)</p>
<p>if __name__ == &quot;__main__&quot;:<br />
 Hoge().execute()<br />

コマンドにhiが表示されたら勝ち。

次に、pythonスクリプトにパラメータを送ろう。 — のつぎに来るものがコマンドとしてパースされないので、pythonに使えばいいね。例えば、今のアセットフォルダの位置を渡してみよう。

<br />
Process.Start (location, file + &quot; &#8211;background &#8211;python &quot; + Application.dataPath + &quot;/Editor/ExportSS.py&quot; + &quot; &#8212; &quot; + new DirectoryInfo(file).Parent.FullName);<br />

**Python側では、sys.argv[sys.argv.index(“–“) + 1:]でパラメータ行列を取れます。

さて意味のあるものができるようになった。できることはさまざまあるが、例としてシーン内の「メッシュではないオブジェクト」の名前を出力してみよう。自明のコードは省略。

<br />
args = sys.argv[sys.argv.index(&quot;&#8211;&quot;) + 1:] #パラメータを取る<br />
scene = bpy.context.scene<br />
obj = bpy.context.active_object<br />
dir = args[0]<br />
name = args[1]</p>
<p>def execute(self):<br />
    if os.access(self.path, os.W_OK) is False:<br />
        print(&quot;permission denied : &quot; + self.dir)<br />
    return False<br />
    self.path = os.path.join(self.dir, self.name + &quot;.txt&quot;)<br />
    print (&quot;writing to: &quot; + self.path)</p>
<p>    with open(self.path, &quot;wb&quot;) as file:<br />
    for obj in self.scene.objects:<br />
        if obj.type != &#8216;MESH&#8217;:<br />
            self.write(file, obj.name + &quot;rn&quot;)<br />
    sys.exit() #自殺</p>
<p>def write (self, file, _str):<br />
    file.write(_str.encode())<br />

すると、.Blendファイルと同じ名前の.txtファイルができます。

以上、拡張機能でした。なんかやりたいときに使えるとうれしい。
では。

Unity5.4でComputeShader(HLSL)のコンパイルに失敗する

Boltzmannです.
ラベリングの並列実装を試みていたところ, あるアルゴリズムを実装したところでUnityに異変が生じました.
具体的には, エディタ(VisualStudio2015を使用)でComputeShader(HLSL)のスクリプトを編集した後, Unityに移行するとUnityがフリーズし, その後PCもフリーズするという状態です.
これが二回ほど起きて, さすがにこれはまずいと思い原因を調べ始めました.

結論から言えば, もっとも考えられる原因はこれでした.
[COMPUTE] HLSLCC TIMES OUT COMPILING COMPLEX SHADERS (BAD PERF ON COMPLEX SHADERS) -Unity Issue Tracker

もともと5.3で作業していて, このページによれば5.4.0で解消されたということで5.4.2にアップグレードして再度試しましたがやはりだめでした.

具体的な症状は, 「Unity Shader Compilerが大量にメモリを食ってからタイムアウトで終了する」というものです.
問題が発生した環境は以下の通りです.
Unity5.3.?(ちゃんとメモしなかった), 5.4.2
CPU:Intel Corei5-5200U
メモリ:8GB
(GPU:Intel HD Graphics 5500)

次にShaderComplierのタスクを以下に載せます. だいぶメモリを食っていることがわかるかと思います.
shadercompilerprofile3

これが5~10分ほど続いて, 最終的にタイムアウトで終了します. タイムアウトで終了するので, シェーダーはコンパイルできていません. この状態でPlayしても以下のようにカーネル関数を見つけることができないというエラーが出ます. (もちろんスクリプト上は存在するカーネル関数です. )
shadercompilertimeout

最後に, この問題が発生した際のスクリプトを記載します. スクリプト全体ではありませんが, この部分をコメントアウトすれば正常にコンパイルされる, という部分を記載します.
なお, 以下のスクリプトの参考文献を次に示します.

柴田直樹, 山本眞也. SumiTag : あまり目立たないARマーカーとGPGPUを利用した読み取り方法. 研究報告マルチメディア通信と分散処理(DPS). 2011, 2011-DPS-149巻, 7号

<br />
    bin = lerp(0, 1, step((float) grayscale, 0.4));<br />
    Input.GetDimensions(width, height);<br />
    index = width * thid.y + thid.x;</p>
<p>    LabelBuffer[index] = bin * index;</p>
<p>    for (i = 0; i &lt; 1000; i++)<br />
    {<br />
        AllMemoryBarrierWithGroupSync();</p>
<p>        label = LabelBuffer[index];<br />
        orig = label;</p>
<p>        if (bin != 0)<br />
        {<br />
            if ((thid.x &gt; 0) &amp;&amp; (label &lt; LabelBuffer[index &#8211; 1]))<br />
                label = LabelBuffer[index &#8211; 1];<br />
            if ((thid.x &lt; width &#8211; 1) &amp;&amp; (label &lt; LabelBuffer[index + 1]))<br />
                label = LabelBuffer[index + 1];<br />
            if ((thid.y &gt; 0) &amp;&amp; (label &lt; LabelBuffer[index &#8211; width]))<br />
                label = LabelBuffer[index &#8211; width];<br />
            if ((thid.y &lt; height &#8211; 1) &amp;&amp; (label &lt; LabelBuffer[index + width]))<br />
                label = LabelBuffer[index + width];</p>
<p>            label = LabelBuffer[LabelBuffer[LabelBuffer[LabelBuffer[label]]]];</p>
<p>            if (label != orig)<br />
            {<br />
                InterlockedMax(LabelBuffer[orig], label);<br />
                InterlockedMax(LabelBuffer[index], label);<br />
            }<br />
        }<br />
    }</p>
<p>    AllMemoryBarrierWithGroupSync();</p>
<p>    switch (LabelBuffer[index] % 20)<br />
    {<br />
        case 0:<br />
            color = float3(1, 0, 0);<br />
            break;<br />
        case 1:<br />
            color = float3(0, 1, 0);<br />
            break;<br />
        case 2:<br />
            color = float3(0, 0, 1);<br />
            break;<br />
        case 3:<br />
            color = float3(1, 1, 0);<br />
            break;<br />
        case 4:<br />
            color = float3(1, 0, 1);<br />
            break;<br />
        case 5:<br />
            color = float3(0, 1, 1);<br />
            break;<br />
        case 6:<br />
            color = float3(0.1, 0.2, 0.5);<br />
            break;<br />
        case 7:<br />
            color = float3(0.2, 0.5, 0.1);<br />
            break;<br />
        case 8:<br />
            color = float3(0.5, 0.1, 0.2);<br />
            break;<br />
        case 9:<br />
            color = float3(0.5, 0.2, 0.1);<br />
            break;<br />
        case 10:<br />
            color = float3(0.1, 0.1, 0.1);<br />
            break;<br />
        case 11:<br />
            color = float3(0.2, 0.2, 0.2);<br />
            break;<br />
        case 12:<br />
            color = float3(0.23, 0.56, 0);<br />
            break;<br />
        case 13:<br />
            color = float3(0.9, 0.2, 0.5);<br />
            break;<br />
        case 14:<br />
            color = float3(0.4, 0.8, 0.2);<br />
            break;<br />
        case 15:<br />
            color = float3(0.4, 0.3, 0.6);<br />
            break;<br />
        case 16:<br />
            color = float3(0.1, 0.3, 0.2);<br />
            break;<br />
        case 17:<br />
            color = float3(0.5, 0.5, 0.2);<br />
            break;<br />
        case 18:<br />
            color = float3(0.5, 0.1, 0.2);<br />
            break;<br />
        case 19:<br />
            color = float3(0.8, 0.8, 0.3);<br />
            break;<br />
        default:<br />
            color = float3(1, 1, 1);<br />
            break;<br />
    }</p>
<p>    Result[thid.xy] = float4(color, bin);<br />

ちなみにswitch文のブロックのみをコメントアウトしても問題は解消されません.
なんとなく, スクリプトを編集しているときの感覚として, InterlockedMaxをfor文の中に組み込んだのがとどめの一撃になった気がします.

とりあえず実装を見直しますが, 実装を誤るたびにUnityが大量にメモリを食ってフリーズするのは勘弁してほしいです.

<2017/2/22 追記>
原因不明として放置してあったのでとりあえずあの後の調査で考えられる原因を書いておこうと思います.
原因として有力なのはコンパイラによるfor文の自動展開です.
GPUデバイスコードは命令数が多いほど並列性が高くなったりするのでコンパイラが可能な範囲で積極的にfor文を展開することがあります.
今回の場合は展開した後のコードがあまりに長くなったためオーバーフローしてフリーズしたのではないかと考えられます.
調べていないので何とも言えませんが, こういった自動展開に関しては必ずそれを制御する#pragmaがあるはずなので, それを使うことで解決できるのではないかと思います.
他の解決策としては, 展開できない程度にコードを複雑にする, というものがあげられます.
上記のスクリプトに関しても, 終了条件をfor (i = 0; i < 1000; i++)のようにべた書きするのではなく, tmp=1000のようにしてからfor (i = 0; i < tmp; i++)のようにすることで回復したように思います.
<追記終わり>

Oculus Rift DK2で使えるコントローラを作ってVR音ゲー作り

お久しぶりです.Kishiです.

一切誰も記事内で触れていませんが,KCSは三田祭に出展します.それに向けたチーム制作も複数動いています.やはり,記事にしないと外部に伝わらないので,それぞれのチームに記事を書いてもらおうかな….

さて,KCSはVR,Virtual Realityにも力を入れています.昨年はOculus Rift DK2を購入してこれを三田祭でのゲーム制作に利用したところ,非常に好評でした.(→VSG

最近の世の中を見ると,HTC ViveやOculus Rift CV1,PlayStation VRが出てきてVR業界は非常に盛り上がっています.KCSは昨年DK2を買ったばかりなので今年の三田祭には昨年同様DK2を用いることになりましたが,ここであることに気づきます.

コントローラがない…!

ナウいVRには皆,VR空間に直接干渉できるコントローラがあります.しかし,DK2にはありません.

そこで,一切のお金を掛けずにコントローラを作ってみました.正確には,昨年サークルで購入したWebカメラと色のついた紙とマスキングテープと労力で作りました.

dk2-controller2

dk2-controller4

簡単に説明すると,色認識をしてコントローラの位置を把握し,これとVR空間内の物体をリンクさせています.(簡単に説明も何もそもそも簡単な原理だった.)

これを使って音ゲーを作りました.音楽はKCSの音楽班が提供してくれました.ありがとうございます.

今年は他にも多くのVRゲームが展示されます.もちろん,VRでないゲームや,KCSの技術力の詰まった(自分には全く理解できない)展示もあります.ぜひお越しください!

量子コンピュータSimulatorを開発しました+量子アルゴリズムの練習をした→悲しい事実に気づく(1)

なぜ量子コンピュータを作ったのか

こんにちは.

今回は,唐突に思いついて作った量子コンピュータシミュレータと,その量子コンピュータを使った量子アルゴリズムの構築法を勉強するための練習についてのお話です.

まず,「量子コンピュータ」と聞くと,一見難しいものと思えるかもしれません.実際,僕も数日前までにはそう思ってました.ところが,数日前に,古典コンピュータ(今皆さんが使っているものです)で数値計算を行うことによって,量子コンピュータの挙動を再現することが可能だということを知りました.このときに,量子コンピュータが実際どういう仕組みで動いているかよくわかっていないことに気付いて,文献を漁って調べてみることにしました.すると,なんだか難しそうだなぁと勝手に思っていたものは,実際にはそんなに難しくなく,再現するための数値計算の手法も難しくないことを知りました.

という経緯があって,量子コンピュータが(数値計算上では)誰にでもつくれるという考えに至り,実際に作ってみようということになりました.

量子コンピュータは何で動くか

古典コンピュータは,AND回路やOR回路などの,複数の古典ビットを何らかの物理的相互作用を用いて変化させることで,様々な情報を処理しています.このことからもわかるように,古典コンピュータの情報の最小単位は,1古典Bitという,0か1かの区別であり,これより小さな情報の単位は存在しません.普段我々が目にしている古典コンピュータは,古典Bitを用いてどのように情報を処理しているのか見ることはありませんが,中身は古典Bitの膨大な操作によって,動いています.これらは,古典Bitをどのように操作するかの技術(≒アルゴリズム)によって支えられています.

一方,量子コンピュータの動作は古典Bitによるものではありません.量子コンピュータの情報の最小単位は「量子ビット(qubit)」と呼ばれるものです.量子ビットは,0か1かの厳密な区別である古典ビットと違い,0か1かの確率的な状態を保持しています.量子ビットは古典ビットではないので,表記法も異なります.例えば,1量子ビットは,a|0>+b|1>のように表記します(ディラックのブラケット記法).ここで,a,bは複素数です.つまり,量子ビットは,0と1がそれぞれa,bだけ含まれる,という状態を保持することができるのです.もちろん,量子ビットは量子(の性質を持つもの)ですから,「観測」を行うことで0か1かが確定します.すなわち,|0>か|1>になるということです.どちらに確定するかは,もともとの量子ビットの状況(a|0>+b|1>)に応じて確率的に決まります.具体的には,a|0>+b|1>である量子ビットが|0>になる確率は,|a|^2で,|1>になる確率は,|b|^2です(このことからもわかるように,|a|^2 + |b|^2 = 1 が満たされる必要があります).ここで重要なポイントは,我々は量子ビットの状態を「観測」せずに知ることができないということです.これは,a,bを直接的に知ることができないということを表しています.

もう一つ,量子ビットについての重要なポイントがあります.それは,量子の「もつれ(entanglement)」です.量子のもつれとは,簡単に言うと,複数の量子Bitがあったとき,複数の量子Bitを観測したときの確率論的独立性がない状態のことです.具体例をあげてみます.今,2つの量子ビットX,Yがあったとします.X,Yがもつれていないときは,XとYを観測したとき,観測されたXの値が0,1どちらであっても,観測されたYが0,1を取る確率は,変わりません.これは,2つのさいころをどうじに投げた状況に似ています.一方のサイコロの目が1だろうが,2だろうが,もう一方のサイコロの目は等しく1/6ですよね.しかしながら,X,Yがもつれているときは,Xの値が0,1どちらになるかによって,Yが0,1どちらになるかの確率が変わってしまうのです.サイコロの例でいうと,2つのサイコロを同じ向きで完全に固定したときに似ています.一方のサイコロの値が1であったら,もう一方は1でしょう.もちろん,一方のサイコロの値が1であったら,もう一方は奇数が出やすくなる,のような例もありですね.このようなもつれ,の状態は,もはや|X>=a|0>+b|1>,|Y>=c|0>+d|1>のような表記はできません.量子がもつれているような状態を表記するためには,|XY>=e|00>+f|01>+g|10>+h|11>のようにします.このような状態の量子ビット群では(X,Y)が(観測したときに)(0,0)を取る確率がe^2,(0,1)を取る確率がf^2,…ということを意味しています.ここまでくればお気づきでしょうが,(任意にもつれさせることのできる)量子ビットがn個あれば,2^n通りの観測結果の確率を表現できます.このことは,非常に重要なことです.すなわち,適切に量子ビットを操作することで,確率的に存在しているあらゆる組み合わせの計算を一度に行える可能性があるということです.

これらの話から,量子コンピュータは,どのようなアルゴリズムで動くのか予想がついた方もいるでしょう.すなわち,量子コンピュータは,量子ビットを操作し,もつれさせ,観測を行うことで,結果を得る,という仕組みです.

量子コンピュータをシミュレートする

と,いうのが量子コンピュータの簡単な説明なのですが,文中に会ったように,結局は,量子の状態は.量子ビット数nに対して,2^n個の複素数で表現できるということです.量子の操作は,この2^n個の複素数を,量子の操作に対応する関数を用いて,写像させることで表現できます.つまり,古典的コンピュータで,量子コンピュータがシミュレート(数値計算で仮想的に実現するということ)することができるということです.よって,作りました(演繹的).

今回は,「量子コンピュータが実装できたよ」ということを示すために,簡単な量子プログラムを作って,結果どうなったかを示したいと思います.そのために,まず(このシミュレータが)量子操作としてどのような操作が行えるのかを,簡単に書いておきます.

.量子ビット数は11qbit.(なぜ,11なのかは,特別な理由はない)

・量子ビット初期化:量子ビットを,任意の確定値にする(|XYZ…>=|01010…>)

・1つの量子ビット(任意)を,パウリ行列(X,Y,Z)とかアダマール行列(H)を用いて変換する.(詳しくは後述)

・1つの制御量子ビット,1つの目標量子ビットを,パウリ行列(X,Y,Z)とかアダマール行列(H)を用いて,制御変換する.(詳しくは後述)

・2つの制御量子ビット,1つの目標量子ビットを,パウリ行列(X)を用いて,制御制御変換する.(詳しくは後述する.)

imagee
量子コンピュータシミュレータ(開発中)の画面

これらの操作機能を持った,量子コンピュータを使って,(僕が勝手に考えた問題)4=x+yを解いてみようと考えた.

…のだが,量子プログラムを書いてからとても残念なことに気づいてしまったのである.

文章が予想以上にながくなったので,これを前半として,前後半に分けて投稿することにする.つづきは,後半で.

 

 

 

 

UnityでUWP(Windows Store)アプリを作るときに気を付けること

こんにちは。Kishiです。

まずは宣伝。以前紹介したアプリの公式ホームページができました。

http://trsasasusu.sakura.ne.jp/spinactioncreator/ja/

では、本題。

Unityは本当に様々なプラットフォームに対応しています。その中にUWP、Universal Windows Platformも含まれています。そこで、せっかくスピンアクションクリエイターをAndroid向けに出しているのだからこちらにも進出してみようということで、Android版から何も変えずにBuild SettingsからSwitch Platformしてビルドしてみました。

すると、エラーが出るわ出るわでビルドできませんでした。

最終的にはリリースまでこぎつけたのですが、そこまでにぶつかった壁を紹介していきます。

1. AES問題

このゲームではAESを用いて暗号化していたのですが、なんとAesManagedなどの暗号化で通常用いられているクラスが使用できないのです。そのため、

<br />
#if NETFX_CORE<br />
// UWP用の処理<br />
#else<br />
// その他のプラットフォーム用の処理<br />
#endif<br />

を用いて他のプラットフォームと分岐させなければなりません。UWP用の暗号化については、 http://qiita.com/utisam/items/4ff154335519650d189b#_reference-834101a5ec3afe6a51acが非常にわかりやすいです。

2. StreamWriterのClose()がない

ただびっくり。Dispose()を使いましょう。

3. シェーダーでTRANSFER_SHADOW(o)が使えない

必要な場所でこれがないと死ぬプラットフォーム(Androidで強制終了くらった)と、これがあると死ぬプラットフォームがあるので注意。

4. タッチのできるデバイスとできないデバイスがある

公式にこれに対応するためのソースコードが出ていますが、以下の

<br />
UnityEngine.WSA.Application.InvokeOnUIThread(() =&gt;<br />
    {<br />
      isInTouchMode =<br />
        UIViewSettings.GetForCurrentView().UserInteractionMode ==<br />
        UserInteractionMode.Touch;<br />
    }, true);<br />

<br />
UnityEngine.WSA.Application.InvokeOnUIThread(() =&gt;<br />
    {<br />
      isInTouchMode =<br />
        Windows.UI.ViewManagement.UIViewSettings.GetForCurrentView().UserInteractionMode ==<br />
        Windows.UI.ViewManagement.UserInteractionMode.Touch;<br />
    }, true);<br />

としないとビルドできません(または、usingするか)。そもそもタッチのできるWindowsデバイスを自分は持っていないので本当に動いているのか検証できていません。(おそらくテスターの方々によるテストを通っているので動作しているのだと思います)

5. Handheld.PlayFullScreenMovie()に注意

StreamingAssetsに入れたビデオが再生されなくてびっくりしました。公式には確かに使えそうなことが書いてあったので。そこで、調べてみるとどこかの海外のフォーラムにて、第1引数を

<br />
&quot;hoge.mp4&quot;<br />

から

<br />
System.IO.Path.Combine(Application.streamingAssetsPath, &quot;hoge.mp4&quot;)<br />

と書き直すと動く、と書いてあったので実際にやってみたら動きました。Android(おそらくiOSも)だったら省略できるのに…。

 

ここからは、.slnを作った後の話です。

6. ここまで来てビルドできない

UWPアプリをUnity以外で普通に開発するときのクラス名と被っているとエラーが出ます。自分はUnityで独自にFileIOクラスを作っていたので、これと被ってエラーを吐かれました。Windows.Storage.FileIOというように名前空間を直接つけて修正しましょう。

7. Debugビルドの実行が異様に遅い

普通の動作テストはReleaseビルドで行いましょう。そして、リリースするときはMasterビルドにしましょう。海外のフォーラムにも結構上がっています。

8. Masterビルドのx64版が死ぬ

正確には、uGUIのScroll Rectが死にます。他にも何か死んでいて、もう実態がつかめないのでx64版はあきらめました。x86版とARM版だけで行きました。

 

ここからはリリース前後の話です。

9. 手続きが大変

これはしょうがないです。決められた大きさのスクリーンショットが必要だったり、課金のために条約が何とかあったりといろいろありますが、がんばりましょう。もちろん認定のために審査があるので、Androidに比べてリリースには時間がかかります。

10. 突然の更新リジェクト

謎。テスターへの文面を英語と日本語両方で丁寧に書いたら通りました。

 

とりあえず、以上です。予想以上に大変でしたが、無事リリースできました(宣伝)

以下の公式バッジは https://developer.microsoft.com/en-us/store/badges で作ることができます。

Get it on Windows 10

スピンアクションクリエイターはWindows Storeで「ゲームを作る」と検索するだけで候補に出てきます。この記事を読んで役に立った方は、ぜひ評価をしていただきたく存じます。そうしていただけるとものすごく嬉しいです(ものすごくものすごく宣伝)

Spin Action Creator スピンアクションクリエイター

お久しぶりです。Kishiです。

前回の自分の記事で8月中にトレーラーを出したいと書いておきながら、気が付けば9月になっておりました。

自分だけのアクションゲームのステージを2Dにおいても、3Dにおいても作成できるゲームです。

https://play.google.com/store/apps/details?id=com.trsasasusu.spinactioncreator

 

Get it on Google Play

以下は動画です。

サムネイル

Screenshot_2016-09-02-00-39-17

Zバッファを可視化するプログラムをUnityで作った.Zバッファを可視化するプログラムをUnityで作った.

これは,Z-Bufferを可視化するプログラムです.

Z-Bufferとは,簡単に言いますと,距離センサーのことです.

カメラからどれくらい離れてるかをしめすんですね.

このZ-Bufferを可視化すると次のようになりました.

キャプチャ.JPGasdfasfasdfafサムネイル

UnityでRawImageを使ってARをする際の備忘録

・Canvasを使うと自動的にカメラの描画範囲にフィットする上、親子関係を作って相対位置を固定する必要がないのでPlaneにはっつけつより楽
・Kinect等と連携してDepthMappingなどをする際にはRenderingPipeLineに入らないといけない気がする

どこをいじったかいまいち覚えていないので全部載っけておく

CanvasのInspector
ARCanvas

RawImageのInspector
ARRawImage

Background.cs

<br />
using UnityEngine;<br />
using System.Collections;<br />
using UnityEngine.UI;</p>
<p>public class Background : MonoBehaviour {</p>
<p>    public WebCamTexture wtex;</p>
<p>    // Use this for initialization<br />
    void Start () {<br />
        if (WebCamTexture.devices.Length &lt;= 0)<br />
        {<br />
            Debug.LogError(&quot;Cannot find a camera. &quot;);<br />
            return;<br />
        }<br />
        this.wtex = new WebCamTexture();<br />
        wtex.Play();</p>
<p>        //tagでUIを表示するCameraを判断<br />
        Camera cam = GameObject.FindGameObjectWithTag(&quot;BattleCamera&quot;).GetComponent&lt;Camera&gt;();</p>
<p>        Canvas canvas = transform.parent.GetComponent&lt;Canvas&gt;();<br />
        canvas.renderMode = RenderMode.ScreenSpaceCamera;<br />
        canvas.planeDistance = cam.farClipPlane-0.01f;<br />
        canvas.worldCamera = cam;</p>
<p>        RawImage rawImage = GetComponent&lt;RawImage&gt;();<br />
        rawImage.texture = wtex;<br />
        //rawImage.SetNativeSize();</p>
<p>        RectTransform recTrans = GetComponent&lt;RectTransform&gt;();<br />
        //recTrans.anchoredPosition = new Vector2(0.5f, 0.5f);<br />
        float scale = ((wtex.width / wtex.height) &gt; cam.aspect) ? ((float)cam.pixelHeight/wtex.width) : ((float)cam.pixelWidth / wtex.height);<br />
        recTrans.sizeDelta = new Vector2(scale * wtex.width, scale*wtex.height);<br />
        recTrans.Rotate(new Vector3(0, 0, -90));</p>
<p>        wtex.Stop();<br />
    }</p>
<p>	// Update is called once per frame<br />
	void Update () {</p>
<p>    }<br />
}<br />

今回の実装はAndroidようだったので、取得したWebcamTextureを90°回転させている
CanvasのRenderCameraに、Canvasを表示させたいカメラを指定するのを忘れないように
UIのRectTransformはTransformに相当する
WebCamTexture.Play()をしないとテクスチャに反映されないため, wtex.widthやwtex.heightが機能しないのでさっさとPlay()しておくこと
今回はゲーム開始時にARモードをいきなり使うわけではないので, 一通りの設定が終わった後にStop()させている.
本当はこのセットアップは画面遷移時にやるべき.

以上.

UnityのInput.gyro.attitudeとInput.accelerationを使ってARをやる際の備忘録

前提:ジャイロセンサによってスマートフォンとカメラを同期、その上で加速度の方向をUnity内部と現実世界で合わせる

<br />
    void Update()<br />
    {<br />
        Quaternion orient = Input.gyro.attitude;<br />
        orient.x *= -1;<br />
        orient.y *= -1;<br />
        Quaternion sub = Quaternion.Euler(90, 0, 0);<br />
        transform.rotation = sub * orient;</p>
<p>        Vector3 accelVecCam = new Vector3( Input.acceleration.x, Input.acceleration.y, -Input.acceleration.z);<br />
        transform.GetChild(0).localPosition = accelVecCam*20; //確認用. 適当なGameObjectをカメラの子にする<br />
    }<br />

accelVecCamはカメラ座標系での加速度ベクトルであることに注意.
World座標にしたいときはtransform.TransformVectorで変換すること.

Input.gyro.attitudeのほう
参考元:http://vr-cto.hateblo.jp/entry/2016/05/02/070000
参考元の参考元:http://qiita.com/fuqunaga/items/b1a3e38af71f062f0781

Input.accelerationのほう
参考元:https://developer.android.com/reference/android/hardware/SensorEvent.html