» チュートリアル エフェクト - 法線
This site relies heavily on Javascript. You should enable it if you want the full experience. Learn more.

チュートリアル エフェクト - 法線

English | Italian | Mandarin

TOC: エフェクトとシェーダー
Back: 頂点データ
Next: ジオメトリモーフィング


位置とテクスチャ座標に加えて、サーフェス法線は3つ目に重要で頂点のデータフィールドの中で最も良く使用されます。法線は頂点位置での表面曲率対する垂線の3Dベクトルです。法線は照明の計算で非常に重要になり、照明ベクトルは表面に影を付けるために表面上で反射されます。

法線の表示

VVVVはメッシュのサーフェス法線を表示するためのヘルパーモジュールを持っています: Normals (EX9)

法線を持ったメッシュの素敵な見た目を得るためにヘルプパッチを変更することができます:

法線の計算

もしメッシュが法線を持っていなければ、シェーダーにメッシュを渡す前に、パッチの中でそれらを計算するために、Normals (EX9.Geometry Mesh)ノードを使うことができます。頂点位置での法線を平均化するためにSmoothing Angleを使いましょう。

多くのシェーディングモデル(phongの様な)はビュー空間での法線を必要とします。それは頂点位置と連動して変形する必要があります。しかし、法線はfloat3またはfloat4で、法線のw成分は0(位置のための1の代わりに)で、移動ではなく回転だけが得られるということに注意しなければなりません。典型的な頂点シェーダーは次の様な変形を行います:

...
    //normal in view space
    Out.NormV = normalize(mul(NormO, tWV));
 
    //position (projected)
    Out.PosWVP  = mul(PosO, tWVP);
    ...

法線の再計算

mr. wiggle表示するための数式のチュートリアルの様に頂点シェーダーで頂点位置を変更する場合、法線の計算はもっと複雑になります。なぜなら頂点位置の移動は表面曲率を変えるからです。メッシュにあらかじめ保存された法線はもはや正しくありません。それゆえにシェーダーの計算は不適切になります。

だから、もしピクセルシェーダーで照明の計算が必要ならば、法線を再計算する方法を見つけなければなりません。しかしこれはとても明確な問題で、あなたが位置を移動した方法に依存します。

新しい頂点の法線を得るための最も一般的ですがそれほど正確ではない方法はすぐ傍らの追加の2つの位置を計算し、この頂点の接平面での2つのベクトルを得ます。そしてそれらは平行ではありません。2つの接線ベクトルから法線を計算するには外積を用います:

  • 現在の位置を計算 p
  • 近傍の位置を計算 n1
  • 近傍の位置を計算 n2
  • 接ベクトルを得る t1 = p - n1
  • 接ベクトルを得る t2 = p - n2
  • 法線を得る n = t1 x t2

表示するための数式のチュートリアルから円錐の例を使えば次の様になります:

float NeighbourOffset = 0.001;
 
vs2ps VS(
    float4 PosO  : POSITION,
    float4 TexCd : TEXCOORD0)
{
    //declare output struct
    vs2ps Out;
 
    //calc new position
    float3 p = Cone(PosO.xy);
 
    //calc neighbour pos in u direction
    float3 n1 = Cone(PosO.xy + float2(NeighbourOffset, 0));
 
    //calc neighbour pos in v direction
    float3 n2 = Cone(PosO.xy + float2(0, NeighbourOffset));
 
    //get tangent vector 1
    float3 t1 = p - n1;
 
    //get tangent vector 2
    float3 t2 = p - n2;
 
    //get normal
    float3 NormO = cross(t1, t2);
 
    //set new pos
    PosO.xyz = p;
    ...

では、vvvvのeffectsフォルダーからPhong関数が宣言されたPhongDirectional.fxhファイルを例として用いて、実際に法線を使ってみましょう。そのために、あなたのシェーダーのそばにファイルをコピーしてPhongDirectional.fxシェーダーの中のphongシェーディングを実行するために必要な行を見つけてください。ビュー空間に入る法線と照明とビュー方向を設置する必要があり、そしてそれら全てをvs2ps構造体の中に入れてピクセルシェーダーに渡す必要があります。素敵なシェーダーを設定するためにテクスチャのためのコードもコピーしましょう。'Cone'関数を全てのweb上で見つけることのできるuvパラメトリックサーフェスで単に置き換えることもできます。

// ----------------------------------------------------------------------------
// PARAMETERS:
// ----------------------------------------------------------------------------
 
//transforms
float4x4 tW: WORLD;        //the models world matrix as via the shader
float4x4 tV: VIEW;         //view matrix as set via Renderer (EX9)
float4x4 tP: PROJECTION;   //projection matrix as set via Renderer (EX9)
float4x4 tWV : WORLDVIEW;
float4x4 tWVP: WORLDVIEWPROJECTION; //all 3 premultiplied 
 
//texture transformation marked with semantic TEXTUREMATRIX
//to achieve symmetric transformations
float4x4 tTex: TEXTUREMATRIX <string uiname="Texture Transform";>;
 
//texture
texture Tex <string uiname="Texture";>;
sampler Samp = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (Tex);          //apply a texture to the sampler
    MipFilter = LINEAR;         //sampler states
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};
 
//the data structure: "vertexshader to pixelshader"
//used as output data of the VS function
//and as input data of the PS function
struct vs2ps
{
    float4 Pos  : POSITION;
    float2 TexCd : TEXCOORD0;
    float3 LightDirV: TEXCOORD1;
    float3 NormV: TEXCOORD2;
    float3 ViewDirV: TEXCOORD3;
};
 
#include "PhongDirectional.fxh"
 
// ----------------------------------------------------------------------------
// VERTEXSHADERS
// ----------------------------------------------------------------------------
 
 
#define twopi 6.28318531
 
float2 Scale = 1;
float2 Offset = 0;
 
float3 Cone(float2 uv)
{
 
     uv *= Scale;
     uv += Offset;
 
    float u = uv.x * twopi;
    float v = uv.y;
 
    float3 newPos;
    newPos.x = v * cos(u);
    newPos.y = v * sin(u);
    newPos.z = v;
 
    return newPos;
}
 
float NeighbourOffset = 0.001;
 
vs2ps VS(
    float4 PosO  : POSITION,
    float4 TexCd : TEXCOORD0)
{
    //declare output struct
    vs2ps Out;
 
    //calc new position
    float3 p = Cone(PosO.xy);
 
    //calc neighbour pos in u direction
    float3 n1 = Cone(PosO.xy + float2(NeighbourOffset, 0));
 
    //calc neighbour pos in v direction
    float3 n2 = Cone(PosO.xy + float2(0, NeighbourOffset));
 
    //get tangent vector 1
    float3 t1 = p - n1;
 
    //get tangent vector 2
    float3 t2 = p - n2;
 
    //get normal
    float3 NormO = cross(t1, t2);
 
    //set new pos
    PosO.xyz = p;
 
    //put normal in view space and normalize it
    Out.NormV = normalize(mul(NormO, tWV));
 
    //inverse light direction in view space
    Out.LightDirV = normalize(-mul(lDir, tV));
 
    //inverse view dir in view space
    Out.ViewDirV = -normalize(mul(PosO, tWV));
 
    //transform position (projected)
    Out.Pos = mul(PosO, tWVP);
 
    //transform texturecoordinates
    Out.TexCd = mul(TexCd, tTex);
 
    return Out;
}
 
// ----------------------------------------------------------------------------
// PIXELSHADERS
// ----------------------------------------------------------------------------
 
float Alpha <float uimin=0.0; float uimax=1.0;> = 1;
 
float4 PS(vs2ps In) : COLOR
{
    float4 col = tex2D(Samp, In.TexCd);
 
    col.rgb *= PhongDirectional(In.NormV, In.ViewDirV, In.LightDirV);
    col.a *= Alpha;
 
    return col;
}
 
// ----------------------------------------------------------------------------
// TECHNIQUES:
// ----------------------------------------------------------------------------
 
technique TFunctionWithPhong
{
    pass P0
    {
        VertexShader = compile vs_1_1 VS();
        PixelShader  = compile ps_2_0 PS();
    }
}

TOC: エフェクトとシェーダー
Back: 頂点データ
Next: ジオメトリモーフィング

anonymous user login

Shoutbox

~3d ago

joreg: vvvvTv S02E01 is out: Buttons & Sliders with Dear ImGui: https://www.youtube.com/live/PuuTilbqd9w

~10d ago

joreg: vvvvTv S02E00 is out: Sensors & Servos with Arduino: https://visualprogramming.net/blog/2024/vvvvtv-is-back-with-season-2/

~10d ago

~11d ago

fleg: hey there! What's the best tool for remote work? Teamviewer feels terrible. Thanks!

~24d ago

joreg: Last call: 6-session vvvv beginner course starting November 4: https://thenodeinstitute.org/courses/ws24-5-vvvv-beginners-part-i/

~1mth ago

joreg: Missed the last meetup? You can rewatch it here: https://www.youtube.com/live/MdvTa58uxB0?si=Fwi-9hHoCmo794Ag

~1mth ago

theurbankind: When is the next big event, like node festival ?

~1mth ago

~1mth ago

joreg: Join us for the next vvvv meetup on Oktober 17th: https://visualprogramming.net/blog/2024/25.-vvvv-worldwide-meetup/

~2mth ago

joreg: 6 session beginner course part 2 "Deep Dive" starts January 13th: https://thenodeinstitute.org/courses/ws24-5-vvvv-beginners-part-ii/