シェーダーの話

シェーダーについて調べるページ

サンプルコード HSP ver3.7ベータ4 

;HSP3.7b4にて動作確認

#include "hgimg4.as" ;hgimg4


screen 0,640,480

setcls CLSMODE_SOLID, $000000 ; 画面クリア設定

gpreset


//カメラ位置

setpos id_camera,0,100,200

gplookat id_camera,0,0,0


//モデル読込

gpload id_model,"res/wave.gpb"//格子に波のテクスチャを張ったモデルを読込


//マテリアルID取得

gpnodeinfo id_mat,id_model2, GPNODEINFO_MATERIAL,"obj1"//モデルのメッシュに対応するマテリアル


//時間管理の変数

time=0.0f


//メイン処理-----------------------------------------

*main


redraw 0

gpmatprm1 id_mat,"u_time",time/2000;頂点シェーダーのuniform変数[u_time]へパラメータを渡す

time++

gpdraw ; 3D描画更新


redraw 1

await 1000/60

goto *main

//--------------------------------------------------

頂点シェーダー(textured_wave.vert)

#ifndef DIRECTIONAL_LIGHT_COUNT

#define DIRECTIONAL_LIGHT_COUNT 0

#endif

#ifndef SPOT_LIGHT_COUNT

#define SPOT_LIGHT_COUNT 0

#endif

#ifndef POINT_LIGHT_COUNT

#define POINT_LIGHT_COUNT 0

#endif

#if (DIRECTIONAL_LIGHT_COUNT > 0) || (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)

#define LIGHTING

#endif


///////////////////////////////////////////////////////////

// Atributes

attribute vec4 a_position;


#if defined(SKINNING)

attribute vec4 a_blendWeights;

attribute vec4 a_blendIndices;

#endif


attribute vec2 a_texCoord;


#if defined(LIGHTMAP)

attribute vec2 a_texCoord1; 

#endif


#if defined(LIGHTING)

attribute vec3 a_normal;


#if defined(BUMPED)

attribute vec3 a_tangent;

attribute vec3 a_binormal;

#endif


#endif


///////////////////////////////////////////////////////////

// Uniforms

uniform mat4 u_worldViewProjectionMatrix;

uniform float u_time;


#if defined(SKINNING)

uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];

#endif


#if defined(LIGHTING)

uniform mat4 u_inverseTransposeWorldViewMatrix;


#if defined(SPECULAR) || (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)

uniform mat4 u_worldViewMatrix;

#endif


#if defined(BUMPED) && (DIRECTIONAL_LIGHT_COUNT > 0)

uniform vec3 u_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];

#endif


#if (POINT_LIGHT_COUNT > 0)

uniform vec3 u_pointLightPosition[POINT_LIGHT_COUNT];

#endif


#if (SPOT_LIGHT_COUNT > 0) 

uniform vec3 u_spotLightPosition[SPOT_LIGHT_COUNT];

#if defined(BUMPED)

uniform vec3 u_spotLightDirection[SPOT_LIGHT_COUNT];

#endif

#endif


#if defined(SPECULAR)

uniform vec3 u_cameraPosition;

#endif


#endif


#if defined(TEXTURE_REPEAT)

uniform vec2 u_textureRepeat;

#endif


#if defined(TEXTURE_OFFSET)

uniform vec2 u_textureOffset;

#endif


#if defined(CLIP_PLANE)

uniform mat4 u_worldMatrix;

uniform vec4 u_clipPlane;

#endif


///////////////////////////////////////////////////////////

// Varyings

varying vec2 v_texCoord;


#if defined(LIGHTMAP)

varying vec2 v_texCoord1;

#endif


#if defined(LIGHTING)


#if !defined(BUMPED)

varying vec3 v_normalVector;

#endif


#if defined(BUMPED) && (DIRECTIONAL_LIGHT_COUNT > 0)

varying vec3 v_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];

#endif


#if (POINT_LIGHT_COUNT > 0)

varying vec3 v_vertexToPointLightDirection[POINT_LIGHT_COUNT];

#endif


#if (SPOT_LIGHT_COUNT > 0)

varying vec3 v_vertexToSpotLightDirection[SPOT_LIGHT_COUNT];

#if defined(BUMPED)

varying vec3 v_spotLightDirection[SPOT_LIGHT_COUNT];

#endif

#endif


#if defined(SPECULAR)

varying vec3 v_cameraDirection;

#endif


#include "lighting.vert"


#endif


#if defined(SKINNING)

#include "skinning.vert"

#else

#include "skinning-none.vert" 

#endif


#if defined(CLIP_PLANE)

varying float v_clipDistance;

#endif


void main()

{

    vec4 position = getPosition();

    position[1] += sin(position[0] + u_time* 100);

    gl_Position = u_worldViewProjectionMatrix * position;


    #if defined(LIGHTING)

    vec3 normal = getNormal();

    // Transform the normal, tangent and binormals to view space.

    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);

    vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);

    

    #if defined(BUMPED)

    

    vec3 tangent = getTangent();

    vec3 binormal = getBinormal();

    vec3 tangentVector  = normalize(inverseTransposeWorldViewMatrix * tangent);

    vec3 binormalVector = normalize(inverseTransposeWorldViewMatrix * binormal);

    mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x, tangentVector.y, binormalVector.y, normalVector.y, tangentVector.z, binormalVector.z, normalVector.z);

    applyLight(position, tangentSpaceTransformMatrix);

    

    #else

    

    v_normalVector = normalVector;

    applyLight(position);

    

    #endif

    

    #endif 

    

    v_texCoord = a_texCoord;

    

    #if defined(TEXTURE_REPEAT)

    v_texCoord *= u_textureRepeat;

    #endif

    

    #if defined(TEXTURE_OFFSET)

    v_texCoord += u_textureOffset;

    #endif

    

    #if defined(LIGHTMAP)

    v_texCoord1 = a_texCoord1;

    #endif

    

    #if defined(CLIP_PLANE)

    v_clipDistance = dot(u_worldMatrix * position, u_clipPlane);

    #endif

}

.materialファイルの覚書

①ユニフォーム変数への値の受け渡し定義(デフォルト抜粋)

 u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX sampler u_diffuseTexture u_ambientColor = 0.6, 0.6, 0.6    u_cameraPosition = CAMERA_WORLD_POSITION    u_inverseTransposeWorldViewMatrix = INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX    u_specularExponent = 1

②techniqueのdefine部分

 technique    {        pass         {            defines = DIRECTIONAL_LIGHT_COUNT 1;BILL_Y 1;BILL_X 1 ←ユーザー定義を使用したい場合には「定義名 値」を「;」セミコロンで区切る        }    }

 シェーダー側では、

 #if defined(BILL_Y) && (BILL_X) ←定義名が有効かどうか判断するプリコンパイル  ~~プログラム #endif

GLSLは、列優先の行列

Unityの「シェーダー」は行優先行列らしい。

https://hsp.tv/play/pforum.php?mode=all&num=100811

https://edom18.hateblo.jp/entry/2019/01/04/153205

(引用)

行列の掛ける順番の意味

最後に、行列の掛ける順番について。

3Dグラフィクスでは行列が頻繁に使われ、特に、頂点シェーダからフラグメントシェーダに値を渡す際、一般的な合成行列を掛けて渡します。

具体的には以下の行列です。

モデル座標変換行列

ビュー座標変換行列

プロジェクション変換行列

そしてそれぞれの行列をひとつに「合算」させたものをシェーダに送り、それを各頂点に掛け算してフラグメントシェーダステージに渡す、というのが基本的な動作です。

そしてこれらの行列の頭文字を取ってM(odel) x V(iew) x P(rojection)でMVP行列、なんて呼ばれたりします。

しかしこれ、行オーダーで計算を行うAPI規則に基づくものです。(つまりDirectX)

Unityでは、上で示したように「列オーダー」となります。

そのため掛ける順番がMVPではなくPVMとなる点に注意が必要です。