2013年12月

2013年12月19日

ぺろっ これは・・





このところ文章の書き方わすれてきたので 生存報告をかねて定期的に更新していきましょう

と心に決めた そんな三日坊主プロなわたしです こんにちは




先日から体調くずして横になってたのですが


朝方 郵便受けに


     「お詫びと廃棄のお願い」 というハガキが入っていました


配達された食品になにか入ってはいけないものが入っていたそうですが たべても心配はないそうです。 

そうか・・ただちに心配はない系なのか..

 

とりあえず理論上は体調と無関係なようです 理論上は

お金は帰ってくるとのことなのですが
もったいないので、ためしにもう一個だけ食べてみようと思います。  

食べて応援 うちの家計



そういえば都知事さんが辞意表明したそうですね  
「ぼく頑張ったのに都知事やめちゃうとか あいた口がふさがらないっすよー 」(カバンさん談
とか カバンさんを擬人化してクスクスやってるのは自分だけでいいです



あと餃子の王将の社長さんが早朝の店の前を清掃中に撃たれて亡くなられたとか 
人生の投了はいつやってくるかわかりませんね。

将来餃子屋社長になるかもしれないのでわたしも早朝に掃除するのを控えようかと思います 
 
まず10時前に起きられる体を目指さないと



なんていうニュースネタも絡めてみました 

ニュースとか見てるんだから情弱じゃないんだからね! といううざいアピールなので気にしないように
まあ まとめサイトしか見てないんですけど




とにかく 感がもどるまでちょっとづつ長文に慣れていこう


それから2年半ご無沙汰だったゲーム関係のはなしとか再開しようかなあ
なんてかんがえてますよ

※これからゲーム業界を目指そうという人は読むと絶望しますのでスルーしてね



ちうわけで いったん寝るよ

気分が悪いのは たぶん風邪ひいてるんだと思いますぇ






おしまい(´・ω・`)

akinow at 15:26|PermalinkComments(2)TrackBack(0) Clip to Evernote 日記 

2013年12月12日

うにばな (エフェクト用のシェーダに関するアイデア1+)

※170607 補足記事をアップしました うにばな スクリーンスペース系のシェーダに関するTips

 

 

今回は”エフェクト用のシェーダに関するアイデア”の補足でGrabTextureを使用する場合のパーティクルのカラー合成をしてみます。

GrabTextureは背景からテクスチャにキャプチャした画像をカラー合成の対象にできる命令で スクリーンサイズのスナップショットをテクスチャに展開します。

GrabTexture命令で 取り込んだテクスチャにシェーダでモデルのカラーを合成をしてやれば ”エフェクト用のシェーダに関するアイデア”で使用したシェーダと同じような効果がねらえます。カラーを合成する式は

これも以前掲載した フォトショップの合成式を使用することが出来るため フォトショップ上の見た目と同等の表現が期待出来て デザイナーにとっては非常にありがたい機能です。 ただしGrabTexture命令は処理負荷が高く現在のモバイルやスマホで動作させるには重ためなので気をつけてください。

 

【fig1】

grabtest

 

 

今回作成したサンプルシェーダコードは以下の通りです

■ 『BlendTest(GrabTex) . shader" 』

Shader "Custom/Particles/BlendTest(GrabTex)" {

    Properties {

        _TintColor ( "Tint Color", Color ) = ( 0.5, 0.5, 0.5, 0.5 )
        _MainTex ( "Particle Texture", 2D ) = "white" {}
  
    }

    Category {

        Tags { "Queue"="Transparent" "RenderType"="Opaque" }
       
          Blend One OneMinusSrcAlpha
         Alphatest Greater 0.1
         ZWrite On
        
        SubShader {

            GrabPass { 
                                                 
                Name "BASE"
                Tags { "LightMode" = "Always" }
  
            }


            Pass {
                Name "BASE"
                Tags { "LightMode" = "Always" }

                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_particles
                #include "UnityCG.cginc"
                #pragma target 3.0

                struct appdata_t {
                    float4 vertex : POSITION;
                    float2 texcoord: TEXCOORD0;
                };

                struct v2f {
                    float4 vertex : POSITION;
                    float4 uvgrab : TEXCOORD0;     
                    float2 uvmain : TEXCOORD2;
                };
   
                sampler2D _GrabTexture;
                float4 _GrabTexture_TexelSize;

                sampler2D _MainTex;
                float4 _MainTex_ST;
               
                fixed4 _TintColor;
              

                v2f vert ( appdata_t v ) {

                    v2f o;

                    o.vertex = mul( UNITY_MATRIX_MVP, v.vertex );
                    #if UNITY_UV_STARTS_AT_TOP
                    float scale = -1.0;
                    #else
                    float scale = 1.0;
                    #endif
                    o.uvgrab.xy = ( float2( o.vertex.x, ( o.vertex.y * scale ) ) + o.vertex.w ) * 0.5;
                    o.uvgrab.zw = o.vertex.zw;           
                    o.uvmain = TRANSFORM_TEX( v.texcoord, _MainTex );

                    return o;

                }


                half4 frag( v2f i ) : COLOR {
            
                   half4 col = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD( i.uvgrab ) );
                   
                   col.a = 0;
                 
                   half4 base = tex2D( _MainTex, i.uvmain);      
                  // このようなブレンド式を使用してもよいです
                 //  return float4( (base.rgb < 0.5 ? (2.0 * base.rgb * col.rgb) : (1.0 - 2.0 * (1.0 - base.rgb) * (1.0 - col).rgb)).rgb , base.a);

                    return float4(base.rgb + _TintColor * pow(base.rgb,2.0 )* col.rgb , base.a);
            

                }
                ENDCG
            }
           
          
        }

    }

}

 

■ GrabTextureの取得は GrabPassをk術するだけです samplerの指定とセットなので記述漏れしないようにしてください

GrabPass
                                                 
                Name "BASE"
                Tags { "LightMode" = "Always" }
  
            }

・・・・・・・・・・・・・・・・・・・・・・・

sampler2D _GrabTexture;

・・・・・・・・・・・・・・・・・・・・・・・

o.uvgrab.xy = ( float2( o.vertex.x, ( o.vertex.y * scale ) ) + o.vertex.w ) * 0.5;
o.uvgrab.zw = o.vertex.zw;
      

 

half4 col = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD( i.uvgrab ) );

Unityのマクロ関数 UNITY_PROJ_COORD にワールド頂点座標を与えることによってカメラのプロジェクション方向から見たスクリーン座標のUV値に変換されます。

Tags { "Queue"="Transparent" "RenderType"="Opaque" } タグはレンダーキュー(Queue)に透明(Transparent)が指定してあればアルファを考慮したソートが行われるため RenderTypeは無視しても構いません。

■Blend One OneMinusSrcAlpha は <背景 1 :前景 1-alpha値> で合成を指定します。アルファ抜きの場合はこれを使用。

ZWriteをOnにするのを忘れないように depthバッファの書き込みが行われないと正確なソートが行われません。

Alphatest Greater 0.1 はしきい値(例の場合0.1)を境界にして透明部分の抜け具合を決定します。


Blend One OneMinusSrcAlpha
        Alphatest Greater 0.1
         ZWrite On


 

■ライブラリの種類によっては取り込んだテクスチャのUV座標のV方向(スクリーン座標のY軸方向)が上下逆になることがあるので

UNITY_UV_STARTS_AT_TOP の変数を監視してテクスチャUVのV方向に−1を掛けてフリップする必要があります


#if UNITY_UV_STARTS_AT_TOP
                    float scale = -1.0;
                    #else
                    float scale = 1.0;
                    #endif

 

■カラー合成式に関してはどのような書き方してももちろん構いません 見た目でより良い結果になるようにしてください。

 

フォトショップのブレンド式 を使用する場合   

return float4( ( base.rgb < 0.5 ? (2.0 * base.rgb * col.rgb) : (1.0 - 2.0 * (1.0 - base.rgb) * (1.0 - col.rgb).rgb)).rgb , base.a );
              

● 加算と乗算を組み合わせる場合

return float4( base.rgb + _TintColor * pow(base.rgb,2.0 )* col.rgb , base.a );

テクスチャはアルファ抜きしたものを使用しますが、 カラーの明度からアルファマスクを計算して取得することも出来ます

【Example】

float alpha =Luminance(color.rgb) ;

たとえばUnityのマクロ関数Luminanceを使用します RGB値カラーを輝度値 に変換する関数で "UnityCG.cginc"ファイルに記述されています

Luminance( ) の代入はfloat3型ですので float4型のカラーを渡すときは 「color.rgb」というようにSwizzleで記述します。

inline fixed Luminance( fixed3 c )
{
    return dot( c, fixed3(0.22, 0.707, 0.071) );
}

 


【追記】

リファレンスには下のように GrabPassにオプションパラメータとしてテクスチャのスケールが指定できると書いてありますが コンパイルが通ったことがありません Unity公式フォーラムでもバグ扱いされていてだれも使い方をわかってないようなんですが、どうやって使用するんでしょう? ご存じの方がいればコメント頂きたいのです。

GrabPass {

    TextureScale 0.5 

   TextureSize 256

    BorderScale 0.3

// following are regular pass commands

    Tags { "LightMode" = "VertexLit" }

    Name "BASE"

}

 

今回は以上です 次回はなるべくはために更新するつもりですが 少しレベルを上げるかもしれませんので頑張って読解してみてください。

質問がある方はコメント欄にどうぞ

 

それではまた



akinow at 08:17|PermalinkComments(0)TrackBack(0) Clip to Evernote Unity3d | シリーズ講座

2013年12月06日

うにばな (Graphics.DrawMesh で高速な描画?)

 

 

drawMeshTest

■webプレイヤー

https://dl.dropboxusercontent.com/u/18978109/DrawMeshTest/DrawMeshTest.html

 

Unity公式のフォーラムで大量のメッシュを描画する方法として有効だというはなしのGraphics.DrawMesh命令を簡単に解説します

Unityの新しいバージョンでプロパティブロックまわりが改良されたそうなので プロパティブロックを使用してサンプルを作成してみました

< どこが新規に変わったのかいまいちわからないのですが >

 

ちなみに情報としては古めなので すでにほかのところに詳しい記事があるかもしれませんが、ここの管理人は怠けものなので国内の記事はあまり見ていません。







■Graphics.DrawMesh

● static function DrawMesh(mesh: Mesh, position: Vector3, rotation: Quaternion, material: Material, layer: int, camera: Camera = null, submeshIndex: int = 0, properties: MaterialPropertyBlock = null): void;

● static function DrawMesh(mesh: Mesh, matrix: Matrix4x4, material: Material, layer: int, camera: Camera = null, submeshIndex: int = 0, properties: MaterialPropertyBlock = null): void;

 

【パラメータ】

mesh描画するメッシュデータ

positionメッシュの位置。

rotation      メッシュの回転。

matrixメッシュの変換行列(位置、回転、その他の変換)。

materialマテリアルを指定する。

layerレイヤを使用する。

camera    :デフォルトはNULL。メッシュはすべてのカメラで描画されますが 指定がある場合指定されたカメラでレンダリングします。

submeshIndex描画するメッシュのどのサブセット。これは、複数の材料で構成されたメッシュに適用される。

propertiesメッシュが描画される直前にマテリアルにプロパティ変更を適用します。※MaterialPropertyBlock

 

DrawMesh命令は1フレームごとにメッシュを描画します。通常のゲームオブジェクトと同様にシェーディングされ影が落ちてプロジェクターの影響を受けることができます。デフォルト状態ではすべてのカメラにレンダリングされますが特定のカメラを指定することもできます。

ゲームオブジェクトの作成と管理のオーバーヘッドを避けて大量のメッシュを描画したい場合DrawMesh命令は有効に機能します。DrawMeshはすぐにメッシュを描画せず Updateの後にレンダリングパイプラインにデータを送り、そのあと通常のレンダリングプロセスの一部としてレンダリングされます。 すぐにメッシュを描画したい場合は、Graphics.DrawMeshNowを使用します。

DrawMeshはすぐにメッシュの描画がされないため、関数の呼び出しの時に材料特性を変更すると、メッシュはそれらをピックアップすることはありません。あなたは、同じマテリアルを用いてメッシュのシリーズを描きたいのですが、すこしだけマテリアルのプロパティ(例えば色を変更)をする場合は、MaterialPropertyBlockのパラメータを使用します。

 





■MaterialPropertyBlock

MaterialPropertyBlockGraphics.DrawMeshによって使用されているRenderer.SetPropertyBlockです。、同じマテリアルで複数のオブジェクトを描画するような場合、たとえばメッシュの色を変更したい場合シェーダ内のプロパティの値を部分的に変更することで対応します。

 

【機能】

AddColor            : カラープロパティを追加します。

AddFloat             :フロート型プロパティを追加します。

AddMatrix         : マトリックス型プロパティを追加します。

AddTexture       :テクスチャ型プロパティを追加します。

AddVector         :ベクター型プロパティを追加します。

Clear                  : プロパティ値のクリア。

GetFloat             : プロパティブロックからフロートを取得します。

GetMatrix          : プロパティブロックから行列を取得します。

GetTexture        : プロパティブロックからテクスチャを取得します。

GetVector          : プロパティブロックからベクトルを取得します。

 

 

【Example】

public class  XXXXX : MonoBehaviour
{

     private MaterialPropertyBlock _PropertyBlock; 
     private int _ColorPropertyId ;

 

void Start()
{

               _PropertyBlock    = new MaterialPropertyBlock();
               _ColorPropertyId = Shader.PropertyToID("_Color");

}

void Update() 
{

               _PropertyBlock.Clear(); 
               _PropertyBlock.AddColor(_ColorPropertyId, Color.white);    
            
  Graphics.DrawMesh( Mesh, Position , Rotation, Material, 0, MainCamera, 0,_PropertyBlock);

  }

}

 

PropertyBlock を効率よく使用するためには1つのブロックを作成してDrawMeshをコールするたびにブロックを再利用する方法です。

Graphics.DrawMesh()の前に使用ブロックをクリアし AddXXX を使用して値を追加します。

指定できるプロパティは使用しているシェーダ内で登録されているプロパティとなります。 複数のシェーダを使用する場合はShader.Find(シェーダ名)で書き換え対象のシェーダを指定する必要があります。

 

 

●DrawMeshManager.cs

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

public class DrawMeshManager : MonoBehaviour
{
   
    public Mesh ObjMesh;
    public Material Material1;
   
    public Camera MainCamera;
    public Transform Player;
    public float ForceDrawWithinDistance = 50.0f;
   
    public int Maxval = 100;
    public float  Scaler = 2.0f;   
   
    private List Objs = new List();
   
    private MaterialPropertyBlock _PropertyBlock;
    private int _ColorPropertyId ;
   
   
    private void Start()
    {
       
        MainCamera = Camera.main;                
        float Offset=(Maxval*Scaler/2.0f)-Maxval*Scaler;
        int ObjectType = 0;
       
        for(var x=0 ; x        {                
            ObjectType = x%2;          
            for(var y=0 ; y            {                   
                for(var z=0 ; z                {    
                                                                
                    ObjData newObj = new ObjData( ObjectType,
                                            new Vector3((float)x*Scaler+Offset,(float)y*Scaler+Offset,(float)z*Scaler+Offset),
                                            Quaternion.Euler(0, 0 ,0));

                    Objs.Add(newObj);                                       
        
                }
           }
           
        }
       
        _PropertyBlock = new MaterialPropertyBlock();
        _ColorPropertyId = Shader.PropertyToID("_Color");       
        
    }

   
    private void Update()
    {
       

        Vector3 playerPosition = Player.position;
        var FrustumPlanes = GeometryUtility.CalculateFrustumPlanes(MainCamera);

        
        float _timer = Time.timeSinceLevelLoad;               
        var ObjBounds = ObjMesh.bounds;
       
        foreach (var Obj in Objs)
        {
                        
        //    int ObjType   = Obj.ObjType; // メッシュオブジェクトを複数定義する場合に使用する
            
                ObjBounds.center = Obj.WorldPosition;

       
            float distance = Vector3.Distance(Obj.WorldPosition, playerPosition);

       
            if (distance < ForceDrawWithinDistance || GeometryUtility.TestPlanesAABB(FrustumPlanes, ObjBounds))
            {
                   
                float ofst = Mathf.Sin((Obj.WorldPosition.y + _timer)/4.0f)*1.5f;
                                
                _PropertyBlock.Clear();
                _PropertyBlock.AddColor(_ColorPropertyId, Obj.Color);   
                Graphics.DrawMesh(ObjMesh, Obj.WorldPosition + new Vector3(ofst,0,ofst) , Obj.Rotation, Material1, 0, MainCamera, 0,_PropertyBlock);
                                          
                    
            }
        }
    }
}

●ObjData.cs 【構造体クラス】

using System;
using UnityEngine;


namespace Assets
{
    public class ObjData
    {
        private  int _ObjType;
        private  Vector3 _WorldPosition;
        private  Quaternion _Rotation;
        private  Color _Color;
       

        public ObjData(int ObjType, Vector3 worldPosition, Quaternion rotation)
        {
            _ObjType = ObjType;
            _WorldPosition = worldPosition;
            _Rotation = rotation;
           
            if (ObjType == 0)
            {
               
                _Color = Color.white;
               
            }
            else
            {

               _Color = new Color(1.0f,0.2f,0.05f);
               
            }      
            
        }

        public Vector3 WorldPosition
        {
            get { return _WorldPosition; }
        }
        public Quaternion Rotation
        {
            get { return _Rotation; }
        }
        public int ObjType
        {
            get { return _ObjType; }
        }       
        public Color Color
        {
            get { return _Color; }
        }
       
    }
}

いままでは配列で管理して結合した後GPUに転送という方法が知られていましたが それにに比べると メモリ消費も少なくて なにより頭を悩ませることがないのがいいですね。

画像のStatisticsで表示されるDrawCall数は3000を越えていますが FPS値はふつうに高いままなので Unityの中身はわからないので想像ですが、おそらくCPU側でGraphics.Draw関数をコールした回数だと思われます。VRAMへの描画は1フレームで行われているらしいです。

左のGUIのFPS表示はエディタから実行した数値です。 PCの環境にもよりますがwebプレイヤーでは60フレーム程度はでていると思います。

Unityのツリーシステムなどでは メモリ使用量はモデルの頂点数分の合計となるためかなり大きめな数値となっています おそらくは内部でメッシュをマージして転送する方法を行っているのだと思いますが、今回のDrawMesh関数を使用するサンプルはアップデート内部でシェーダにモデル1つ分のデータを送るだけなのでGPU側のメモリはほとんど消費されていません

それからスキンモデルにもDrawMwshを使用してみたいところなのですが現時点ではスキンウェイトのモデルはダイナミックバッチがかからない仕様になっているそうなのです

スキニングのフィルターがブラックボックスなので調べてみないとわかりませんが、アニメーションするキャラクターを大量に配置したい場合はスキンウェイト用のシェーダを自作する必要があるかもしれません。



akinow at 09:46|PermalinkComments(0)TrackBack(0) Clip to Evernote Unity3d | シリーズ講座