まゆたまガジェット開発逆引き辞典

電子工作やプログラミングのHowtoを逆引き形式で掲載しています。作りたいモノを決めて学んでいくスタイル。プログラマではないので、コードの汚さはお許しを。参照していないものに関しては、コピペ改変まったく問いません

Processingで立方体をランダムな位置&ランダムな方向に回転させる

イラストの背景用にまた自動生成グラフィックを使ってしまったのでメモ。
楽なんですもの・・・

下記の画像のように、ランダムな方向を向いた立方体をランダムな位置に配置しました。
マウスを押すと新たに描画してくれます。
好きな画像が生成されるまで、マウスをクリックします。

f:id:prince9:20190121052624p:plain

Processingは3Dで描画した場合はPDF書き出しができないので(私のやり方が悪いのかも)、PNGで書き出してフォトショやイラレでテクスチャを貼ります。
Processing上でテクスチャを貼っても良いのですが、あまりキレイじゃない気がするので、そこは妥協しました。


 float rotX, rotY, rotZ;
  float boxsize;
  float posx, posy, posz;  

void setup(){
size(600, 600, P3D);
  smooth();
  noLoop();
  
}
void draw(){
  background(255,255,255);
  translate(width/2, height/2, 200);
  

   //20個描く
  for(int i=0; i<20; i++){
    boxcity();
  }
}
 
void boxcity(){
boxsize = 30; //奥行きで大きさが決まるので、立方体のサイズは一定でいいかも

//以下、立方体の位置
    posx = random(-100, 100);  
    posy = random(-100, 100);
    posz = random(-100, 100);


    
    fill(0,0,0);
  stroke(255);
 strokeWeight(2);
    pushMatrix();
    translate(posx, posy, posz); 
    box(boxsize, boxsize, boxsize);
    popMatrix();
    
    //立方体の回転角度
    rotX = random(10, 340);
    rotY = random(10, 340);
    rotZ = random(10, 340);
    
    rotateX(radians(rotX));
        rotateY(radians(rotY));
            rotateZ(radians(rotZ));


}

  
//ボタンを押すとランダムに描画
void mousePressed() {
      redraw();// ボタンが押されたときだけ実行
}

なお立方体の描画に関して、下記を参照させて頂きました。

http://solo-p5.tumblr.com/post/69249477759/p3dとboxとarrayとjavajsモードの違いとtips
solo-p5.tumblr.com

バ美声を使ってボイスチェンジする(設定あり)

つい最近ベータ版が発表されてそのクオリティの高さが評判となった「バ美声」を使ってボイチェンをしてみました。
halfsode.booth.pm

配信側の設定は下記をご参照ください。
prince9.hatenablog.com


物理女性声→高い女性声へチェンジしたところ、よく知られている「恋声」よりもクオリティが高かったです(個人調べ)。
地声(女性にしては少し低め)→バ美声→バ美声の順番です。

soundcloud.com


設定は下記と変わりませんが、一応載せておきました。
prince9.hatenablog.com

■バ美声→VST使用可能アプリ(REAPERやCubaseなど)
1.Windowsサウンド設定
・「再生」のタブの「スピーカー」を右クリックし、「既定のデバイス」を選択する。Viveのイヤホン端子またはヘッドセットの出力を既定のデバイスにする
・「録音」のタブの「VoiceMeeter Output」を右クリックし、「既定のデバイス」を選択する(「VoiceMeeter Banana」インストール済み)
f:id:prince9:20181021185832p:plain
f:id:prince9:20181021185954p:plain

・さらにViveを使って配信する場合は、SteamVRを下記のように設定する
f:id:prince9:20181021191045p:plain


2.「VB-CABLE」をダウンロード&インストールした状態で、バ美声の設定を下記のようにする
www.vb-audio.com

・入力デバイス:「Viveのマイク(3-HTC Vive)」またはヘッドセットのマイク
・出力デバイス:「CABLE Input」
f:id:prince9:20190117192631p:plain

3.VST使用可能アプリ(REAPERやCubaseなど)で下記のように設定する
・確認+録音する場合
f:id:prince9:20190117192744p:plain

・配信にゲストとして参加する場合
f:id:prince9:20181021195946p:plain

ShaderGraphで灯篭的なものをつくる

トゥーンシェーダで影がドットのものを作りたくなったので、ShaderGraphで作ってみることにしました。
ShaderGraphとは、シェーダを線のようなもので繋いで作成していくものです。
今回はその練習として、UVスクロールのShaderを作ってみます。要するにテクスチャがアニメーションして動くものですね。

インストールの準備をする

※注意 ShaderGraphの使い方をググると、ProjectManagerからShaderGraphをインストールしようなどの項目が出てきますが、2018年11月下旬において、それを行うとShaderGraphで作ったファイルが保存できません。
現状このやり方でできますので、注意が必要です。
テンプレートではなく新しくプロジェクトを作って、ProjectManagerから各種ファイルをインストールしても同様の結果でした。
すでに作ったプロジェクトを「Edit」メニュー→Render Piepeline→Update Project Materials To Lightweight Materialsを選んで、「Processed」を押してアップデートしても同様でした。

1.Unityのプロジェクトを作る。このとき、「Template」を「Lightweight RP(Preview)」にする
f:id:prince9:20181123114229p:plain
2.テンプレート画面が出てくるので、「Assets」を右クリックして、「Create」→「Scene」で新しいシーンをつくる
3.「GameObject」メニュー→「3D Object」→「Cube」などでテストモデルを作成する
4.「Assets」にドットのテクスチャをドラッグ&ドロップで読み込ませておく

Shaderをつくる

1.「Asstes」を右クリックし、「Create」→「Shader」→「PBR Graph」を選択して「RollShaderGraph」など名前をつける
2.「RollShaderGraph」をクリックした状態で、右クリックし、「Create」→「Material」でマテリアルを作成して「RollMat」など名前をつける
3.「RollShaderGraph」をダブルクリックし、ShaderGraphを立ち上げる

ノードをつくる

1.テクスチャを表示する
→テクスチャのRGB(4)を「PBR Master(最終出力)」の「Albedo」につなぐ
f:id:prince9:20181123152922p:plain

2.テクスチャを手動でスクロールさせる
2-1.ShaderGraphの画面で右クリックして「Create Node」を選択→「Input」→「Basic」→「Slider」でスライダーを表示する
2-2.下記のようにノードを接続する

全体:
f:id:prince9:20181123153752p:plain

部分:
f:id:prince9:20181123153711p:plain
f:id:prince9:20181123153725p:plain
f:id:prince9:20181123153737p:plain

2-3.「Slider」のスライダを動かして、テクスチャが動けばOK


3.自動でテクスチャがスクロールさせる
3-1.「Sider」をクリックし、右クリックして「Convert to Property」を選択する。これでInspectorからSliderの値をコントロールできる
f:id:prince9:20181123163421p:plain
3-2.どこでもいいので右クリックして、「Create Node」で「Multiply」を選択する
3-3.同じように「Time」を選択する
3-4.「Property(元Slider)」から「Combine」に伸びている線をクリックし、右クリックで「Delete」を選んで消す
f:id:prince9:20181123164008p:plain
3-5.「Time」「Property」「Multiply」を下記のように接続する
f:id:prince9:20181123164306p:plain
3-6.「Multiply」と「Combine」を下記のように接続する
f:id:prince9:20181123164344p:plain
3-7.ShaderGraph画面左上の「Save Asset」を押して適用する

最終的に、
全体:
f:id:prince9:20181123164538p:plain
部分:
f:id:prince9:20181123164602p:plain
f:id:prince9:20181123164619p:plain
f:id:prince9:20181123164630p:plain

ShaderGraphで作ったシェーダを適用する

1.「RollMat」を選択し、「Shader」のところを「RollShaderGraph」にする
2.「RollMat」をオブジェクトにドラッグ&ドロップする
3.「RollMat」をクリックし、「Isnpector」の「Vector1」で回転速度を変える。0なら停止状態
※マシンスペックによっては、Sceneビューのみ回転していてGameビューは停止状態ということもあり。Playボタンを押せばちゃんと動くので問題はない
f:id:prince9:20181123165011p:plain

スクリプトでライトをコントロールする

こちらでも扱っていますが、たまに忘れるのでメモ代わりに。
prince9.hatenablog.com

注意点としては、スクリプトを直接ライトにつけると、プレイ時にエラーが出ます。
空のオブジェクトを作って、「public GameObject slight」などにしてライトをドラッグ&ドロップする必要があります。

準備

下記の3点を作ります。
・空のゲームオブジェクト(「GameObject」メニュー→「Create Empty」
・明るさをコントロールしたいライト
スクリプト(「Assets」を右クリックして、C# Script)

スクリプト

1.スクリプトを空のゲームオブジェクトにドラッグ&ドロップする
2.空のゲームオブジェクトをクリックし、Inspectorの「slight」にコントロールしたいライトをドラッグ&ドロップする

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

public class LightScript : MonoBehaviour {

//以下2つ必須
public GameObject slight;
float LIntensity;

	// Use this for initialization
	void Start () {
		LIntensity = slight.GetComponent<Light>().intensity;
		
	}
	
	// Update is called once per frame
	void Update () {
		//ライトの明るさ
		LIntensity = 100f;
		slight.GetComponent<Light>().intensity = LIntensity;
		
	}
}

同じプロジェクト間、違うスクリプトでのデータの受け渡し

同じプロジェクトの別のスクリプトで変数とそのデータを使いまわしたいことがあります。
そのときのデータを受け渡し(正確には読み取り)のメモです。

準備

1.「GameObject」メニュー→「Create Empty」で空のオブジェクトを2つ作る
2.それぞれの名前を「Send」「Recieve」などにする。同じ名前にしないよう気をつける
3.「Assets」を右クリックしてスクリプトを2つ作り、「SendScript」「RecieveScript」などと名前をつける
4.「Send」オブジェクトには「SendScript」を、「Recieve」オブジェクトには「RecieveScript」をドラッグ&ドロップする
5.「SendScript」と「RecieveScript」をダブルクリックしてスクリプトを書く

スクリプト 「SendScript」データを送る方(参照先)

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

public class SendScript : MonoBehaviour {

//この値を「RecieveScript」に送る(参照する)
public int ScoreData = 100;

	void Start () {
		
		

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

スクリプト 「RecieveScript」データを受け取る方(処理する先)

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

public class recieveScript : MonoBehaviour {

//この2つの変数が必要
 GameObject scoreBox;
SendScript script; 


	// Use this for initialization
	void Start () {
	
//Sendというオブジェクトを探す
		scoreBox = GameObject.Find ("Send");
        script = scoreBox.GetComponent<SendScript>();

//新しく変数を作って、「SendScript」の変数「ScoreData」を入れる
		int score = script.ScoreData;

        Debug.Log ("スコアは" + score);


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


    
}

VRMキャラクターの表情を一定時間ランダムに変える

こちら2つの応用編です。コルーチン使用部分はたぶん力技。
prince9.hatenablog.com
prince9.hatenablog.com


マイクの最大音量を計測し、そのときにランダムに表情を変えるというスクリプトを書いてる途中のメモです。
キーボードを押すごとにランダムに表情が変わり、2秒後に元に戻ります。

準備

こちらを参考にして、必要な表情を作成しておきます。
prince9.hatenablog.com

スクリプト

「BlendList = new List(){"Neutral","Smile","Setunai","SHINKEN"};」で使いたい表情をリスト化します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRM;

public class FaceKeep : MonoBehaviour {
private VRMBlendShapeProxy proxy;


public List<string> BlendList;
private string rBlend;

//「処理を止める処理」を停止するか否か
bool isRunning = false;

	// Use this for initialization
	void Start () {
//使いたい表情のリスト
		BlendList = new List<string>(){"Neutral","Smile","Setunai","SHINKEN"};
		
	}
	
	// Update is called once per frame
	void Update () {
		

if (proxy == null)
        {
            proxy = GetComponent<VRMBlendShapeProxy>();
        }
        else
        {
			//上矢印キーをキーコードで判断
	if(Input.GetKeyDown(KeyCode.UpArrow)) {

//ランダムにリストから表情を選ぶ
		rBlend = BlendList[ Random.Range(0, BlendList.Count) ];
           Debug.Log(rBlend);

		proxy.SetValue(rBlend, 1.0f);

//時を止める処理
		StartCoroutine(TimeStop());

	} else {
			proxy.SetValue(BlendList[0], 1.0f);





	}
			


		}
		
	}

	IEnumerator TimeStop() {  
		//「処理を止める処理」を開始する
	if( isRunning ) { yield break; }
	isRunning = true;

//2秒時を止める
		yield return new WaitForSeconds(2.0f);

//2秒後表情を通常に戻す
		proxy.SetValue(rBlend, 0f);
				proxy.SetValue(BlendList[0], 1.0f);

				//「処理を止める処理」を停止する(動き出す)
isRunning = false;

	}
}

一定以上のボリュームのときに大きさが変わる

音量が一定以上になったときにキャラクターの表情を変えたいと思い、そのテストとしてやってみました。
一定以上のボリュームになったら、オブジェクトのサイズと色が変わります。
ただ実際に実装したいのが「表情」なので、サイズと色が変わったらそれを2秒保持する(=2秒次の処理を止める)ことを行なっています。
瞬間的に表情が変わり続けるのはどうかと思うので・・・

数秒後に処理を行う、など時間を扱う処理である「コルーチン」を使いましたが、力技なような気がしてます。

大きさの変化に関して参考にさせて頂いたのがこちら。
tips.hecomi.com

前準備 再生したいサウンドファイルを設定する

スクリプトを書いて、オブジェクトにコードをドラッグ&ドロップします。
そうするとInspectorに「Audio Source」の項目ができるので、▶︎をクリックして「AudioClip」に再生したいサウンドファイルをドラッグ&ドロップします。

スクリプト

状態を保持する時間を作っているので、音との同期が確実に正確ではありませんが、実験ではまあまあでした。

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

/* 
ボリュームに合わせてオブジェクトの大きさを変えたい場合に必要
using System.Linq;
*/

[RequireComponent(typeof(AudioSource))]	


public class SoundMoveScript : MonoBehaviour {

//256を1024にするともっと細かく検出できる
float[] wData = new float[256];

//「処理を止める処理」を停止するか否か
bool isRunning = false;



private AudioSource audioS;

	// Use this for initialization
	void Start () {
		
       audioS = GetComponent<AudioSource>();
	   
		
	}
	
	// Update is called once per frame
	void Update () {

/* 
ボリュームの変化に合わせてオブジェクトの大きさを変える場合はここだけ。他の変数との兼ね合いで変数名を変えてますが、例ほぼそのままです
		AudioListener.GetOutputData(wData, 1);
        var volume = wData.Select(x => x*x).Sum() / wData.Length;
        transform.localScale = Vector3.one * volume * 10;

		*/


		
		 float vol = GetMaxVolume();
		  Debug.Log(vol);
 
//ボリューム最大値が0.5以上のとき

   if(vol >= 0.5) {
	   gameObject.GetComponent<Renderer>().material.color = Color.blue;
	   transform.localScale = new Vector3(4, 4, 4);

   } 
  
    else {
		//0.5以上になったときの処理を停止する=状態を保持して、次の状態へ移行する
		StartCoroutine(TimeStop());


	}
 
 

	}


	float GetMaxVolume()
{ 

    float a = 0;
    audioS.GetOutputData(wData,0);
    foreach(float vMax in wData)
    {
    //最大値を取り出す
		a += Mathf.Max(vMax);
    }
	  
    return a/256.0f;
	
}


 



IEnumerator TimeStop() {  
	//「処理を止める処理」を開始する
	if( isRunning ) { yield break; }
	isRunning = true;


 	//2秒止める(状態を保持する)
  yield return new WaitForSeconds(2.0f);

//次の処理へ移行
	transform.localScale = new Vector3(1, 1, 1);
	gameObject.GetComponent<Renderer>().material.color = Color.red;

		//2秒止める(状態を保持する)
	yield return new WaitForSeconds(2.0f);
	//「処理を止める処理」を停止する(動き出す)
isRunning = false;



}


}