LoginSignup
7
1

More than 5 years have passed since last update.

AndroidでComputeShaderのテスト

Last updated at Posted at 2017-06-15

環境

Unity5.6.1f1

概要

AndroidでComputeShaderのテストをしてみました

追記(2017/06/22)

最近のスマホだとPSIZEがちゃんと動作するみたいなのでコードを変更しました

スマホ対応状況

以下で確認できます
http://hwstats.unity3d.com/mobile/gpu.html

OpenGlES3.1の設定

・「BuildSettings」でAndroidに「SwitchPlatform」する
・「PlayerSettings」>「OtherSettings」>「AutoGraphicsAPI」のチェックを外す
・「GraphicAPIs」リストから「OpenGLES2」を削除する
・「RequireES3.1」もしくは「RequireES3.1+AEP」のどちらかにチェックをする

ComputeShaderの作成

・プロジェクトビューで右クリックし、「Create」>「Shader」>「ComputeShader」を押す

エディタでエラー「Platform does not support compute shaders」

・解決できないので、エディタ上でテストする時はPCに「SwitchPlatform」する

プログラム

Assets/TestComputeShader.cs
デフォルトのコンピュートシェーダ(シェルピンスキーのギャスケット的なの)とポイントクラウドです

using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class TestComputeShader : MonoBehaviour
{
    [SerializeField] private ComputeShader _computeShader = null;
    [SerializeField] private RawImage _rawImage = null;
    [SerializeField] private Material _materialParticle = null;
    [SerializeField] private RawImage _rawImageCamera = null;
    private RenderTexture _renderTexture = null;
    private ComputeBuffer _particles = null;

    private IEnumerator Start()
    {
        yield return TestDefault();
        yield return TestParticle();
    }

    private void OnDestroy()
    {
        if( _particles != null )
            _particles.Release();
    }

    private IEnumerator TestDefault()
    {
        var groupNum = 32;
        var threadNum = 8;  //computeShaderのnumthreadsの値
        var texSize = groupNum * threadNum;

        _renderTexture = new RenderTexture( texSize, texSize, 0, RenderTextureFormat.ARGB32 );
        _renderTexture.enableRandomWrite = true;
        _renderTexture.Create();
        _rawImage.texture = _renderTexture;

        var kernelIndex = 0;
        var kernelName = "TestDefault";
        kernelIndex = _computeShader.FindKernel( kernelName );
        _computeShader.SetTexture( 0, "Result", _renderTexture );
        _computeShader.Dispatch( kernelIndex, groupNum, groupNum, 1 );

        yield break;
    }

    struct Particle
    {
        Vector3 position;
        Color color;
    };
    private IEnumerator TestParticle()
    {
        var camera = Camera.main;
        var texHeight = 1920;
        var texWidth = texHeight * camera.aspect;
        var renderTexture = new RenderTexture( (int)texWidth, texHeight, 0, RenderTextureFormat.ARGB32 );
        camera.targetTexture = renderTexture;
        _rawImageCamera.texture = renderTexture;

        var groupNum = 4;
        var threadNum = 8;  //computeShaderのnumthreadsの値
        var size = groupNum * threadNum;
        var particleBufferSize = size * size * size;

        _particles = new ComputeBuffer( particleBufferSize, Marshal.SizeOf( typeof( Particle ) ) );

        var kernelIndex = 0;
        var kernelName = "TestParticle";
        kernelIndex = _computeShader.FindKernel( kernelName );
        _computeShader.SetInt( "Size", size );
        _computeShader.SetBuffer( kernelIndex, "Particles", _particles );

        var elements = new float[16];
        while( true )
        {
            var rot = Quaternion.Euler( 0.0f, transform.localRotation.eulerAngles.y + 1.0f, 0.0f );
            transform.localRotation = rot;

            var pos = transform.localPosition;
            pos.z = Mathf.Sin( Time.time ) * 5.0f;
            transform.localPosition = pos;

            var wm = transform.localToWorldMatrix;
            for( int i = 0; i < elements.Length; i++ )
                elements[ i ] = wm[ i ];

            _computeShader.SetFloats( "ObjectToWorld", elements );
            _computeShader.Dispatch( kernelIndex, groupNum, groupNum, groupNum );
            yield return null;
        }

        yield break;
    }

    private void OnRenderObject()
    {
        if( _particles == null )
            return;
        _materialParticle.SetPass( 0 );
        _materialParticle.SetBuffer( "Particles", _particles );
        Graphics.DrawProcedural( MeshTopology.Points, _particles.count );
    }
}

Assets/ComputeShader.compute

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#pragma kernel TestDefault

RWTexture2D<float4> Result;

[numthreads( 8, 8, 1 )]
void TestDefault( uint3 id : SV_DispatchThreadID )
{
    Result[ id.xy ] = float4( id.x & id.y, ( id.x & 15 ) / 15.0, ( id.y & 15 ) / 15.0, 1.0 );
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#pragma kernel TestParticle

struct Particle
{
    float3 position;
    float4 color;
};
RWStructuredBuffer<Particle> Particles;
int Size;
float4x4 ObjectToWorld;

[numthreads( 8, 8, 8 )]
void TestParticle( uint3 id : SV_DispatchThreadID )
{
    int index = ( id.z * ( Size * Size ) ) + ( id.y * Size ) + id.x;
    Particles[ index ].position = float3( id.xyz ) / float( Size - 1 ) - 0.5;
    Particles[ index ].position = mul( ObjectToWorld, float4( Particles[ index ].position, 1.0 ) ).xyz;
    Particles[ index ].color = float4( float3( id.xyz ) / float( Size ), 1.0 );
}

Assets/Particle.shader
#pragma target 5.0を入れないと正常に表示されません

Shader "Custom/TestParticle"
{
    Properties
    {
    }

    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 5.0

            #include "UnityCG.cginc"

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 color : COLOR;
                float psize : PSIZE;
            };

            struct Particle
            {
                float3 position;
                float4 color;
            };
            StructuredBuffer<Particle> Particles;

            v2f vert( uint id : SV_VertexID )
            {
                v2f o;
                o.vertex = UnityObjectToClipPos( float4( Particles[ id ].position, 1.0 ) );
                o.color = Particles[ id ].color;
                o.psize = 16.0 / o.vertex.w;
                return o;
            }

            fixed4 frag( v2f i ) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}
7
1
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
7
1