AkiIroブログ

初心者なりにUnityとVRまわりのことについて書いていきます。

【Unity】CloudBuildをつかって作ったiOSアプリ(IPA)をコマンドラインでiTunesConnectにアップする.

ITunesConnectにアップロードする

p12ファイルとProvisioning Profileの作成は終わっていて,CloudBuildは動いているものとします.
f:id:AkiIro:20180121022605p:plain
こんな感じですね.

こういう状況になっていない人は,こちらの記事様がわかりやすいかと思います. macdays.hatenablog.com blog.naichilab.com

今回はCloudBuildからダウンロードできるIPAをiTunesConnectにアップロードする方法です.
CloudBuildを行うとIPAファイルをダウンロードできますが,直接iTunesConnectにアップロードする仕組みはないようです.

altool

altoolというものを使います.これはXcodeに付属しています.
簡単に使えるようにPATHにいれてしまうことをおすすめします.
パス名の途中にスペースがあるのでご注意ください.

export PATH=$PATH:/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/

ターミナルを開き直すか,以下のコマンドで更新します.

source ~/.bash_profile

これでaltoolが簡単に使えるようになりました.

アップロード

altool --upload-app -f NAME.ipa -u MAIL@ADDRESS -p PASS

大文字のところは適宜変えてください.
なお,Windowsの方はApplication Loaderというものを使う必要があるようです.(一ヶ月だけ無料です.)

ここで,PASSの部分ですが,App用パスワードが必要です.
設定していない方はこちらを参考に用意してください. support.apple.com

以上になります.

参考

blog.kishikawakatsumi.com

【Unity】キャラクターをポイントクラウド化するスクリプト

Meshtopologyを変更する

実際はMeshtopologyを変更するだけです.
こんなことができます.
f:id:AkiIro:20171118232721p:plain
youtu.be

つまり可愛くはなりません.

使い方

f:id:AkiIro:20171118231351p:plain
アタッチしてスクリプトの上で右クリックしてGo.
以上です.
終わったらRemoveComponentしてください.

ソースコード

Modify MeshTopology with one button.

解説みたいなもの

既存のモデルのメッシュをコピーしてから,トポロジを変更します.
コピーしないと既存のモデルのメッシュが壊れます.壊しました.
元のモデルのとこにメッシュのコピーが作られます.
点の大きさはまた別の処理が要ります.
このあたりです.

notargs様 wordpress.notargs.com

参考

Unity Forum
https://forum.unity.com/threads/how-do-i-duplicate-a-mesh-asset.35639/

【Unity】uGUIのImageに空間フィルタをかけるシェーダー

uGUIのImageに対するフィルタ処理をGPUでやれます.ご自由にお使いください.

フィルタ処理

f:id:AkiIro:20171115033633p:plain ソーベルフィルタの例
マテリアルのプロパティを変えれば色々な3x3の空間フィルタがかけられます.

ソースコード

Unity ShaderLab "Custom/UI/Filtered" uGUIのImageに空間 ...

インスペクタ

f:id:AkiIro:20171115033906p:plain Cutoutを0以外にすれば明るさが低い部分を切り捨てられます.

シェーダーだけで完結するためにマトリクスを作る部分で無駄があります.
ご了承ください.

【Unity】AudioListerを録音してwavにする

録音する

Unity内で鳴っている音をそのまま録音します.
ソースコードはこちら.

using System;
using System.IO;
using System.Text;
using UnityEngine;

[RequireComponent(typeof(AudioListener))]
public class AudioListener2Wav : MonoBehaviour {
    private int m_outputRate = 44100;
    private bool m_isRecording = false;
    private FileStream m_stream;
    readonly private string m_fileName = "recTest.wav";
    readonly private int m_headerSize = 44;
    float[] wave = new float[1024];

    void Update ()
    {
        if (!Input.GetKeyDown(KeyCode.R)) return;
        if (m_isRecording == false)
        {
            Debug.Log("rec started",this);
            m_isRecording = true;
            startWriting(m_fileName);
        }
        else {
            m_isRecording = false;
            writeHeader();
            Debug.Log("rec stop", this);
        }
    }

    private void OnAudioFilterRead(float[] data, int channels)
    {
        if (!m_isRecording) return;
        convertAndWrite(data);
    }

    /// <summary>
    /// ストリームを0埋めして初期化
    /// </summary>
    /// <param name="name">ファイルの名前</param>
    private void startWriting(string name)
    {
        m_stream = new FileStream(name, FileMode.Create);
        var emptyByte = new byte();
        for (int i = 0; i < m_headerSize; i++) {
            m_stream.WriteByte(emptyByte);
        } 
    }

    /// <summary>
    /// 変換してストリームに書き込む
    /// </summary>
    /// <param name="dataSource">書き込むデータ</param>
    private void convertAndWrite(float[] dataSource)
    {
        Int16[] intData = new Int16[dataSource.Length];
        var bytesData = new byte[dataSource.Length*2];
        int rescaleFactor = 32767;
        for (int i = 0; i < dataSource.Length; i++) {
            intData[i] = (short) (dataSource[i] * rescaleFactor);
            var byteArr = new byte[2];
            byteArr = BitConverter.GetBytes(intData[i]);
            byteArr.CopyTo(bytesData, i * 2);
        }
        m_stream.Write(bytesData, 0, bytesData.Length);
    }

    /// <summary>
    /// ヘッダを書く
    /// 詳しくはwavのフォーマットを確認
    /// http://www.graffiti.jp/pc/p030506a.htm
    /// </summary>
    private void writeHeader()
    {
        m_stream.Seek(0, SeekOrigin.Begin);
        
        Byte[] riff = Encoding.UTF8.GetBytes("RIFF");
        m_stream.Write(riff, 0, 4);
        Byte[] chunkSize = BitConverter.GetBytes(m_stream.Length - 8);
        m_stream.Write(chunkSize, 0, 4);
        Byte[] wave = Encoding.UTF8.GetBytes("WAVE");
        m_stream.Write(wave, 0, 4);
        Byte[] fmt = Encoding.UTF8.GetBytes("fmt ");
        m_stream.Write(fmt, 0, 4);
        Byte[] subChunk1 = BitConverter.GetBytes(16);
        m_stream.Write(subChunk1, 0, 4);

        UInt16 one = 1;
        UInt16 two = 2;
        Byte[] audioFormat = BitConverter.GetBytes(one);
        m_stream.Write(audioFormat, 0, 2);
        Byte[] numChannels = BitConverter.GetBytes(two);
        m_stream.Write(numChannels, 0, 2);

        Byte[] sampleRate = BitConverter.GetBytes(m_outputRate);
        m_stream.Write(sampleRate, 0, 4);

        Byte[] byteRate = BitConverter.GetBytes(m_outputRate * 4);
        // sampleRate * bytesPerSample*number of channels, here 44100*2*2
        m_stream.Write(byteRate, 0, 4);

        UInt16 four = 4;
        Byte[] blockAlign = BitConverter.GetBytes(four);
        m_stream.Write(blockAlign, 0, 2);

        UInt16 sixteen = 16;
        Byte[] bitPerSample = BitConverter.GetBytes(sixteen);
        m_stream.Write(bitPerSample, 0, 2);

        Byte[] dataString = Encoding.UTF8.GetBytes("data");
        m_stream.Write(dataString, 0, 4);

        Byte[] subChunk2 = BitConverter.GetBytes(m_stream.Length - m_headerSize);
        m_stream.Write(subChunk2, 0, 4);

        m_stream.Close();
    }
}

同じGameObjectにAudioListenerがいないと
OnAudioFilterReadがコールされません.(ハマりました)

使い方

  1. AudioListerのついたGameObjectにアタッチ
  2. Rボタンを叩く(録画開始)
  3. 再度Rボタンを叩く(録画終了)

参考

参考にした元のソースはこちらにあります. ただしこちらはUnityScriptです.
https://forum.unity3d.com/threads/writing-audiolistener-getoutputdata-to-wav-problem.119295/

【Unity】DrawMesh初歩と動的Mesh生成

DrawMesh

APIはこれです.

docs.unity3d.com

これを使うことでアクティブなGameObjectを存在させずにMeshを描くことができます.
つまりその分軽量なわけです.

大抵は膨大な数(1,000,000とか)のパーティクルを扱う際に活躍する技術のようですが, 今回は初歩的に一つのMeshを描きます.
Meshは事前に用意せずに動的に生成してみます.
動的なMeshの生成に関してはこちらの記事がわかりやすいです.

www.shibuya24.info

コード

using UnityEngine;

public class DynamicMeshUsingDrawMesh : MonoBehaviour {
    [SerializeField]
    Material m_mat;
    Mesh m_mesh;

    void Start () {
        // 動的Mesh生成
        m_mesh = new Mesh();
        m_mesh.vertices = new Vector3[] {
            new Vector3 (-0.5f, -0.5f),
            new Vector3 (0.5f, -0.5f),
            new Vector3 (0.5f, 0.5f),
            new Vector3 (-0.5f, 0.5f),
        };
        m_mesh.uv = new Vector2[]
        {
            new Vector2(0,0),
            new Vector2(1f,0),
            new Vector2(1f,1f),
            new Vector2(0,1f),
        };
        m_mesh.triangles = new int[] {
            0, 1, 2,
            0, 2, 3,
        };
        m_mesh.RecalculateNormals();
        m_mesh.RecalculateBounds();
    }
    private void Update()
    {
        Graphics.DrawMesh(m_mesh, Vector3.zero, Quaternion.identity, m_mat, 0); 
    }
}

マテリアルはなんでもいいですが,今回は適当に赤いマテリアルをつけます. f:id:AkiIro:20170705001231p:plain

実行結果

f:id:AkiIro:20170705001008p:plain
動的にMeshを生成して描画できました.

【Slide】ゲームエンジンアーキテクチャの5章ざっくりまとめ

先日,ゲームエンジンアーキテクチャをみんなで読む機会があり,5章についてまとめましたので需要は不明ですがこちらに掲示します.
5章エンジンサポートシステムを担当しました.
Unityをはじめとして強力なエンジンが無料で使える時代に,ゲームエンジンを組む意味を確認する一助として.

Windowsでpthread

Windowsでpthreadのコンパイル

Windowsに環境をpthreadをコンパイルする環境を構築した際のメモ書きです.
参考にさせていただいたサイト様はこちら
【VC++】スレッド(pThread)を利用する環境を整える
私はVC++のようなIDEではなく,エディタとgccで行いましたが,基本は同じです.

pthread.h等々をダウンロード

Windowsにはpthreadのライブラリが標準で入っていません.
なのでこちらのリンクからライブラリ類をダウンロードし,インクルードパスにおいてあげることが必要です.
pthread win32

  • includeの下に置くもの
    • pthread.h
    • sched.h
    • semaphore.h
  • libの下に置くもの
    • libpthreadGC2.a
    • libpthreadGCE2.a
    • pthreadVC2.lib
    • pthreadVCE2.lib
    • pthreadVSE2.lib
  • binの下に置くもの
    • pthreadGC2.dll
    • pthreadGCE2.dll
    • pthreadVC2.dll
    • pthreadVCE2.dll
    • pthreadVSE2.dll

ボールドの部分は参考サイトにはありませんでしたが,私の環境では入れないとライブラリがなくコンパイルがうまくいきませんでした.

ちなみにインクルードパス諸々は次のコマンドで調べられます.

gcc -print-search-dirs

‘timespec’: ‘struct’ type redefinitionを解決する

windowsのtime.hには,既にtimespecが定義されていて,
pthread.hのインクルードガードはこれに対応していません.
したがって手っ取り早いのは,

#define HAVE_STRUCT_TIMESPEC
#include <pthread.h>

こうしてしまうことです.

後はコンパイルするだけです.

gcc -o thread thread.c -lpthreadGC2