3

Google で調べましたが、Photoshop を使用して作成する方法に関するチュートリアルしか見つかりませんでした。無関心!その背後にあるロジックが必要です。(そして、バンプ マップを「使用」する方法のロジックは必要ありません。バンプ マップを「作成」する方法を知りたいです!)

私は独自の HLSL シェーダーを作成しており、2 つのピクセル間に何らかのグラデーションがあり、その法線を示すことを認識しています。したがって、ライトの位置に応じて点灯させることができます。

テクスチャが変更されたときにバンプマップも変更されるように、これをリアルタイムで行いたいと考えています。

ありがとう

4

4 に答える 4

2

高さまたは深度マップを読み取るためのサンプラー。

/// same data as HeightMap, but in a format that the pixel shader can read
/// the pixel shader dynamically generates the surface normals from this.
extern Texture2D HeightMap;
sampler2D HeightSampler = sampler_state
{
    Texture=(HeightMap);
    AddressU=CLAMP;
    AddressV=CLAMP;
    Filter=LINEAR;
};

私の入力マップは 512x512 の単一コンポーネント グレースケール テクスチャであることに注意してください。そこから法線を計算するのは非常に簡単です。

#define HALF2 ((float2)0.5)
#define GET_HEIGHT(heightSampler,texCoord) (tex2D(heightSampler,texCoord+HALF2)) 
///calculate a normal for the given location from the height map 
/// basically, this calculates the X- and Z- surface derivatives and returns their  
/// cross product. Note that this assumes the heightmap is a 512 pixel square for no particular  
/// reason other than that my test map is 512x512. 
float3 GetNormal(sampler2D heightSampler, float2 texCoord) 
{ 

      /// normalized size of one texel. this would be 1/1024.0 if using 1024x1024 bitmap. 
    float texelSize=1/512.0; 

    float n = GET_HEIGHT(heightSampler,texCoord+float2(0,-texelSize)); 
    float s = GET_HEIGHT(heightSampler,texCoord+float2(0,texelSize)); 
    float e = GET_HEIGHT(heightSampler,texCoord+float2(-texelSize,0)); 
    float w = GET_HEIGHT(heightSampler,texCoord+float2(texelSize,0)); 


    float3 ew = normalize(float3(2*texelSize,e-w,0)); 
    float3 ns = normalize(float3(0,s-n,2*texelSize)); 
    float3 result = cross(ew,ns); 

    return result; 
}

そして、それを呼び出すピクセル シェーダー:

#define LIGHT_POSITION (float3(0,2,0))

float4 SolidPS(float3 worldPosition : NORMAL0, float2 texCoord : TEXCOORD0) : COLOR0
{
    /// calculate a normal from the height map    
    float3 normal = GetNormal(HeightSampler,texCoord);
    /// return it as a color. (Since the normal components can range from -1 to +1, this 
      /// will probably return a lot of "black" pixels if rendered as-is to screen.
    return float3(normal,1);        
} 

LIGHT_POSITIONホスト コードから入力することができます (そして、おそらく入力する必要があります) が、ここでは定数をだまして使用しました。

この方法では、法線ごとに 4 つのテクスチャ ルックアップが必要であることに注意してください。色を取得するために 1 回は数えません。それはあなたにとって問題ではないかもしれません(あなたが何をしているかによって異なります)。それがパフォーマンス ヒットになりすぎる場合は、テクスチャが変更されるたびにそれを呼び出し、ターゲットにレンダリングし、結果を法線マップとしてキャプチャすることができます。

別の方法として、高さマップでテクスチャリングされた画面に位置合わせされたクワッドをレンダー ターゲットに描画し、ddx/ ddyHLSL 組み込み関数を使用して、ソース テクスチャを再サンプリングすることなく法線を生成することができます。明らかに、パス前のステップでこれを行い、結果の法線マップを読み返し、それを後の段階への入力として使用します。

いずれにせよ、これは私にとって十分に速いことが証明されました。

于 2012-05-23T12:53:29.417 に答える
0

簡単に言えば、これを確実に実行して良い結果を生み出す方法はありません。これは、でこぼこによって色/明るさが変化する拡散テクスチャと、色/明るさが変化する拡散テクスチャを区別する方法がないためです。その時点で表面が実際には異なる色/明るさであるためです。

より長い答え:

表面が実際には一定の色であると仮定すると、色や明るさの変化は凹凸による陰影効果によるものに違いありません。実際の表面の色から各ピクセルがどれだけ明るい/暗いかを計算します。明るい値は、光源に「向いている」表面の部分を示し、暗い値は、光源から「離れている」表面の部分を示します。光が来る方向も指定すると、テクスチャの各ポイントでサーフェス法線を計算して、計算したシェーディング値が得られるようにすることができます。

それが基本理論です。もちろん、実際には、サーフェスが一定の色になることはほとんどありません。そのため、純粋に拡散テクスチャを入力として使用するこのアプローチはうまく機能しない傾向があります。CrazyBump のようなものがどのようにそれを行うのかはわかりませんが、テクスチャ全体ではなく、画像の局所的な部分の色を平均化するようなことをしていると思います。

通常、法線マップは、低解像度のジオメトリに「投影」されたサーフェスの実際の 3D モデルから作成されます。結局のところ、法線マップは高解像度のジオメトリを偽造するためのテクニックにすぎません。

于 2012-06-10T23:04:51.463 に答える
-1

クイックアンサー: 不可能です。
単純な汎用 (拡散) テクスチャには、この情報が含まれていません。Photoshop がどのように機能するかを正確に調べたわけではありませんが (アーティストが使用したことがあるのを見たことがあります)、単に 'depth=r+g+b+a' のようなことを行うだけで、基本的に高さマップ/グラデーションを返します。次に、単純なエッジ検出エフェクトを使用して高さマップを法線マップに変換し、接線空間の法線マップを取得します。

ほとんどの場合、法線マップを使用して高解像度の 3D ジオメトリ メッシュをシミュレートします。シーンがライティングに大きく依存している場合、これは使用できませんが、単純なディレクショナル ライトの場合、これは機能する可能性があります。もちろん、これは私の経験にすぎません。まったく別の種類のプロジェクトに取り組んでいる可能性もあります。

于 2012-05-23T12:18:28.447 に答える