goo blog サービス終了のお知らせ 

日々適当

hibitekitou

「頂点シェーダーとフラグメントシェーダーの例」の検証 3

cg |2019-05-13

頂点シェーダーとフラグメントシェーダーの例 [Unity マニュアル]

「ワールド空間法線を使った環境リフレクション」の検証

「法線マップを使った環境リフレクション」の検証

Shader "Unlit/SkyRefrection Per Pixel"
{
    Properties
    {
        _BumpMap("Normal Map", 2D) = "bump"{}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f {
                float3 worldPos: TEXCOORD0; 
                
                //接空間のベクトルをワールド空間に変換するために使うのが以下の三つ。3x3の回転行列ということです。
                //接空間はテクセル位置に接する平面を基準とした空間。
                //  テクセルはテクスチャの画素ぐらいの意味。
                //tspace0,tspace1,tspace2 の3つの3Dベクトルで3x3行列を構成するようです。
                half3 tspace0 : TEXCOORD1;
                half3 tspace1 : TEXCOORD2;
                half3 tspace2 : TEXCOORD3;
                
                float2 uv : TEXCOORD4; //法線マップのテクスチャ座標
                float4 pos : SV_POSITION; 
            };
            
            //バーテックスシェーダーの関数。
            v2f vert (float4 vertex : POSITION, float3 normal: NORMAL, float4 tangent: TANGENT, float2 uv: TEXCOORD0){
                //シェーダーセマンティクス
                //  float4 TANGENT : 接線。
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                o.worldPos = mul(unity_ObjectToWorld , vertex). xyz;
                
                half3 wNormal = UnityObjectToWorldNormal(normal); //法線
                half3 wTangent = UnityObjectToWorldDir( tangent. xyz ); //接線
                //TANGENTは4DベクトルなのでUnityObjectToWorldDirにかけるためにxyzを取り出している。
                half3 tangentSign = tangent.w * unity_WorldTransformParams.w;
                //tangentの向き(w 1か-1を返す?)に
                //(おそらく)オブジェクトが裏返っているかいないかを判断する
                //unity_WorldTransformParams.w(1か-1を返す?)をかけて接戦の方向を確定しているのだと思う。
                half3 wBitangent = cross(wNormal, wTangent) * tangentSign; //従接線
                //法線と接線の外積からこの二つのベクトルに直行するベクトルに向きを考慮して従接線(従法線)を得ている。
                
                o.tspace0 = half3( wTangent.x, wBitangent.x , wNormal.x );
                o.tspace1 = half3( wTangent.y, wBitangent.y , wNormal.y );
                o.tspace2 = half3( wTangent.z, wBitangent.z , wNormal.z );
                //この3つで回転行列になるらしい。
                //接空間で表現されたベクトルにこの回転行列を適用するとワールド座標系で表現されたベクトルになる、らしい。
                
                o.uv = uv;
                return o;
                
            }
            
            sampler2D _BumpMap; //法線マップテクスチャ
            
            //フラグメントシェーダーの関数
            //オブジェクトが画面上でしめる全てのピクセルで実行されるプログラム。
            fixed4 frag (v2f i): SV_Target {
                
                half3 tnormal = UnpackNormal(tex2D(_BumpMap , i.uv));
                //法線マップはUnityに読み込まれた段階で圧縮フォーマットとして内部で保持される。
                //それを適切な法線の値として再現するためのUnpackNormalメソッド。
                
                //以下取り出した法線を接空間からワールド空間に変換。
                half3 worldNormal;
                worldNormal.x = dot(i.tspace0, tnormal);
                worldNormal.y = dot(i.tspace1, tnormal);
                worldNormal.z = dot(i.tspace2, tnormal);
                //接空間のベクトルにワールド座標系への回転行列を適用することと、上記3つの内積を使用した式は同じ。
                //wTangent = (tx, ty, tz) , wBitangent = (bx, by,bz), wNormal = (nx,ny,nz) とするなら
                //下式の3x3行列が回転行列。これをtnormal = (x,y,z)に適用する。
                //┌        ┐┌ ┐ ┌                  ┐
                //│tx bx nx││x│ │tx*x + bx*y + nx*z│
                //│ty by ny││y│=│ty*x + by*y + ny*z│
                //│tz bz nz││z│ │tz*x + bz*y + nz*z│
                //└        ┘└ ┘ └                  ┘
                //となり、右辺の各項は
                //tspace0とtnormalの内積、
                //tspace1とtnormalの内積、
                //tspace2とtnormalの内積とそれぞれ同じになる。
            
                half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                //ピクセルごとのカメラへの方向を取得して
                half3 worldRefl = reflect(-worldViewDir, worldNormal);
                //そのピクセルでの反射のベクトルを得る。
            
                half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
                //unity_SpecCube0 : Unityがデフォルトで定義しているキューブマップ
                //UNITY_SAMPLE_TEXCUBE:指定したベクトル方向のキューブマップの色を返す。
                
                half3 skyColor = DecodeHDR( skyData , unity_SpecCube0_HDR );
                //DecodeHDRはUnityCG.cgincに入っている関数らしいです。
                //unity_SpecCube0_HDRはunity_SpecCube0のHDRに関する情報が入っていると考えればいいのでしょうか。
                //skyDataは内部形式で保持されている色を本来の色にデコードするのがDecodeHDR、なのか?
                
                fixed4 c = 0;
                c.rgb = skyColor;
                return c;
            }
            
            ENDCG
        }
    }
}
コメント ( 0 )|Trackback ( )
 
コメント
 
コメントはありません。
コメントを投稿する
ブログ作成者から承認されるまでコメントは反映されません
 
名前
タイトル
URL
コメント
コメント利用規約に同意の上コメント投稿を行ってください。

数字4桁を入力し、投稿ボタンを押してください。