LoginSignup
10
12

More than 5 years have passed since last update.

[Unity]GLSLをiPadProで表示する備忘録

Last updated at Posted at 2016-02-26

Tokyo Demo Fest 2016の会場にて
GLSLをiOSで表示するまでの備忘録。

GLSL Sandboxたのしい

このサイト
http://glslsandbox.com/

https://www.shadertoy.com/
を開いて、気になる絵をクリックすれば
GLSLの世界が待っています。

メガデモ好きにはたまらない。

今回はこれをiPadProで表示しようと試みる

http://glslsandbox.com/e#30967.4
image

この顔を表示しようと思う。

Tokyo Demo Fest 2016 GLSL Compoでの@notargs さんの作品が元ネタ。
解像度の落とし方とかも教えてもらいました。

試して問題になった点/解決方法

・そのままではiOSで表示できなかった。→グラフィック設定を変更して解決。
・解像度依存でShader処理が行われて、描画フレームレートがでない(なめらかなアニメーションにならない)→Shaderの解像度を下げる

解像度を下げるために
カメラ2つとかレンダーターゲットとか使うのでごちゃごちゃしますので注意。

UnityでShaderを用意

image
Create>ShaderでShaderを作る

中身

Shader "Custom/GLSL Shader" {

    Properties {
        _MicInput ("_MicInput", Float) = 0
        _Size ("_Size", Float) = 1
        _Speed ("_Speed", Float) = 1
    }

    SubShader {
        Pass {
            GLSLPROGRAM

#ifdef VERTEX
void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif

#ifdef FRAGMENT

#define PI 3.1415926535

uniform vec4 _ScreenParams;
uniform vec4 _Time;
uniform float _MicInput;
uniform float _Size;
uniform float _Speed;

float time = _Time.x;
float s = _Size;
float speed = _Speed;
//vec2 resolution = vec2(_ScreenParams.x, _ScreenParams.y);


//uniform float time = _Time.x;
vec2 mouse = vec2(0.5, 0.5);
vec2 resolution = vec2(_ScreenParams.x, _ScreenParams.y);//vec2(560.5, 560.5);

float rand(float a, float b)
{
    return fract(sin(dot(vec2(a, b) ,vec2(12.9898,78.233))) * 43758.5453);
}

void main( void ) {
    time = _MicInput;//_Time.x;

    vec2 pos = ( gl_FragCoord.xy - resolution.xy / 2.) / resolution.y + mouse - 0.5;
    pos.y = -pos.y;
    vec3 color = vec3(0, 0, 0);

    for(int i = 0; i < 200; i++)
    {
        float fi = float(i);
        float t  = time;//pow(fract(time * 2.), 0.5);
        float t2 =     floor(time * 2.);
        float a = float(i) / PI;
        float len = s*0.3 + (1. - t) * 0.2 * rand(fi, 0.);
        vec2 p = pos + vec2(cos(a), sin(a)) * len;
        float intencity = pow(0.003 / length(p), 1.5);
        color += intencity * vec3(rand(fi, 1.), rand(fi, 2.), rand(fi, 3.));
    }
    for(int i = 0; i < 20; i++)
    {
        float fi = float(i);
        float t  = pow(fract(time * 2.), 0.1);
        float t2 =     floor(time * 2.);
        float a = float(i - 10) / PI / 5.;
        float len = s*0.3 + (1. - t) * 0.2 * rand(fi, 0.);
        vec2 p = pos + vec2(sin(a), cos(a)) * len;
        p += vec2(0, -0.1);
        float intencity = pow(0.003 / length(p), 1.5);
        color += intencity * vec3(rand(fi, 1.), rand(fi, 2.), rand(fi, 3.));
    }
    for(int i = 0; i < 20; i++)
    {
        float fi = float(i);
        float t  = time;//pow(fract(time * 2.), 0.1);
        float t2 =     floor(time * 2.);
        float a = float(i - 10) / PI;
        float len = s*0.04 + (1. - t) * 0.2 * rand(fi, 0.);
        vec2 p = pos + vec2(sin(a), cos(a)) * len;
        p += vec2(-0.13, -0.05);
        float intencity = pow(0.003 / length(p), 1.5);
        color += intencity * vec3(rand(fi, 1.), rand(fi, 2.), rand(fi, 3.));
    }
    for(int i = 0; i < 20; i++)
    {
        float fi = float(i);
        float t  = time;//pow(fract(time * 2.), 0.1);
        float t2 =     floor(time * 2.);
        float a = float(i - 10) / PI;
        float len = s*0.04 + (1. - t) * 0.2 * rand(fi, 0.);
        vec2 p = pos + vec2(sin(a), cos(a)) * len;
        p += vec2(0.13, -0.05);
        float intencity = pow(0.003 / length(p), 1.5);
        color += intencity * vec3(rand(fi, 1.), rand(fi, 2.), rand(fi, 3.));
    }
    color += vec3(fract(pos.y * 20. + time) < 0.5) * 0.05;
    color += vec3(fract(pos.y * 20. - time) < 0.5) * 0.05;
    gl_FragColor = vec4(color, 1.0);

}
#endif
            ENDGLSL
        }
    }
}

ほぼそのままコピーしても動く。
ただMicInputとかSizeとかSpeedとかで変更できるようにちょっといじっています。
あと、あとで問題になったので、y軸反転してます。

環境はUnity5.3.1p4 Macでやってます。

マテリアルを用意

Shaderを適用したマテリアルを用意

image

これで適当なBoxとか作って、マテリアルを指定すれば・・・
image
と、いう感じで表示されます。

void main( void ) {
    time = _MicInput;//_Time.x;

この行の_MicInputをやめて_Time.xコメント側にして、Unity実行すれば、時間変化もします。

iOSではそのままでは表示されない

初期状態のままiPad側でみるとピンクの画面がでてしまいます。
たぶんShaderが処理できていない。ので

PlayerSettingのAuto Graphics APIのチェックを外して
OpenGLES2、Metalの順にしています。

image

iPadProだとカクカクする

iPadProの解像度でのレンダリングはさすがにスペック的に厳しいので、
軽くするテクニックを教わりました。

直接Shaderが動くとすべてのピクセル処理しようとするので大変。
そこで、解像度を落としてごまかします。

ここでは、カメラを2つ使います。低い解像度のカメラと通常のメインカメラ。

低い解像度用のカメラを用意

image

今回のShader(Smile)をカメラでとらえます。
このカメラはSmileレイヤーしか撮影しないように設定し、
Qualに先ほどのShaderを貼り、LayerをSmileにしておきます。

低い解像度用のカメラの結果をテクスチャにする

Create>Rander Textureを作り・・・

image

Cameraのtarget Textureに設定
image

サイズを512x512くらいにしておく
image

メインカメラを用意

image

メインカメラは普段のカメラと同じように扱います。

テクスチャのマテリアルを用意する

さきほどの低い解像度のカメラの撮影結果をもつマテリアルを用意し、Quadに貼り付けます。

image

メインカメラでQuadを表示すれば、画面一杯に引き伸ばされた512x512テクスチャの別カメラでとらえたShaderの結果が表示されます。

これで、最終レンダリングサイズに依存しない固定サイズでのShaderの結果を得られるので、速度重視な場合に使えます。(画質は落ちるけど、仕方ないね)

おまけ Micの入力で動かしたかった

スクリプトからShaderのパラメータを弄ってみます。
とりあえずタッチでいろいろ変わるようにしています。

using UnityEngine;
using System.Collections;

public class MicInput : MonoBehaviour
{
    AudioSource aud;

    // Use this for initialization
    void Start()
    {
        foreach (string device in Microphone.devices) {
            Debug.Log("Name: " + device);
        }

        aud = GetComponent<AudioSource>();

        aud.clip = Microphone.Start(null, true, 10, 44100);  // マイクからのAudio-InをAudioSourceに流す
        aud.loop = true;                                      // ループ再生にしておく
        aud.mute = true;                                      // マイクからの入力音なので音を流す必要がない
        while (!(Microphone.GetPosition("") > 0))
        {
        }             // マイクが取れるまで待つ。空文字でデフォルトのマイクを探してくれる
        aud.Play();                                           // 再生する

        Debug.Log("Mic Start");    

        Renderer renderer = this.gameObject.GetComponent<Renderer>();
        material = renderer.sharedMaterial;//.GetComponent<Material>();
    }
    Material material;

    float size = 1;

    void Update()
    {
        float vol = Input.acceleration.x;//GetAveragedVolume();
        //Debug.Log(vol.ToString());    

        #if UNITY_EDITOR_OSX
        {

            //if(vol == 0)
            {
                vol = Input.mousePosition.x/Screen.width;
                vol += Mathf.Sin(Time.timeSinceLevelLoad*20f)*0.05f;
            }

            material.SetFloat("_Size",Input.mousePosition.y/Screen.height);
            material.SetFloat("_Speed",Input.mousePosition.x/Screen.width);
        }

        #else
        {  
            if(Input.touchCount == 1)
            {
                {
                    size = Input.touches[0].position.x/Screen.width;
                }
            }
            if(Input.touchCount == 2)
            {
                material.SetFloat("_Speed",Input.touches[1].position.y/Screen.height);
            }

            vol += Mathf.Sin(Time.timeSinceLevelLoad*20f)*0.05f;
        }
        #endif 

        material.SetFloat("_Size",size);
        material.SetFloat("_MicInput",vol);//Mathf.Sin(Time.timeSinceLevelLoad));
    }

    float GetAveragedVolume()
    { 
        float[] data = new float[256];
        float a = 0;
        aud.GetOutputData(data, 0);
        foreach (float s in data)
        {
            a += Mathf.Abs(s);
        }
        return a / 256.0f;
    }
}

なんだか、Unity5.3.1だとMic入力しても音量0でしか来なかったので加速度で置き換えてしまってます。
(iOSの問題か、Unityの問題か切り分けできていない)

10
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12