9

適用可能なオブジェクトにランダムな輝きを追加する非常に単純なシェーダーを作成しようとしています。これを行う方法は、ピクセル シェーダー内のピクセル値に白 (R = G = B) のランダムな色合いを追加することです。

それはnoise()私が望むようには機能しないようです:

float multiplier = noise(float3(Input.Position[0], Input.Position[1], time));

への呼び出しを参照すると、「エラー X4532: 式をピクセル シェーダー命令セットにマップできません」というメッセージが表示されnoise()ます。

シェーダーの呼び出し間で数値を保持する方法がわからないため、レンダリング前に渡されたシードに基づいて単純な乱数生成関数を作成することはできないと思います。

ピクセル シェーダー内から乱数を生成する方法はありますか? 方法があるとすれば、どのように?

4

4 に答える 4

26

2017年7月の更新:「疑似ランダム性」をより安定させました

// Version 3
float random( vec2 p )
{
    vec2 K1 = vec2(
        23.14069263277926, // e^pi (Gelfond's constant)
         2.665144142690225 // 2^sqrt(2) (Gelfond–Schneider constant)
    );
    return fract( cos( dot(p,K1) ) * 12345.6789 );
}

これはバージョンです:

float random( vec2 p )
{
   // e^pi (Gelfond's constant)
   // 2^sqrt(2) (Gelfond–Schneider constant)
     vec2 K1 = vec2( 23.14069263277926, 2.665144142690225 );

   //return fract( cos( mod( 12345678., 256. * dot(p,K1) ) ) ); // ver1
   //return fract(cos(dot(p,K1)) * 123456.); // ver2
     return fract(cos(dot(p,K1)) * 12345.6789); // ver3
}

// Minified version 3:
float random(vec2 p){return fract(cos(dot(p,vec2(23.14069263277926,2.665144142690225)))*12345.6789);}

ノイズを生成するためにテクスチャを渡すことは、(通常)過剰に設計されています。便利な場合もありますが、ほとんどの場合、乱数を計算する方が簡単で高速です。

シェーダー変数はフラグメントごとに独立しているため、それらの間で既存の変数を再利用することはできません。その場合、問題は「適切な」乱数シードを使用する方法の1つになります。無理数はそもそも法案に適合しているようです。次に、それは良い「順列」関数を選ぶという「単純な」問題です。

これがトリックを行ういくつかの無料のコードです:

// Input: It uses texture coords as the random number seed.
// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
// Author: Michael Pohoreski
// Copyright: Copyleft 2012 :-)
// NOTE: This has been upgraded to version 3 !!
float random( vec2 p )
{
  // We need irrationals for pseudo randomness.
  // Most (all?) known transcendental numbers will (generally) work.
  const vec2 r = vec2(
    23.1406926327792690,  // e^pi (Gelfond's constant)
     2.6651441426902251); // 2^sqrt(2) (Gelfond–Schneider constant)
  return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );  
}

数式を構成要素に分解すると、これがどのように機能するかを理解するために、何が起こっているのかを視覚化するのが簡単になります。

const vec2 k = vec2(23.1406926327792690,2.6651441426902251);
float rnd0( vec2 uv ) {return dot(uv,k); }
float rnd1( vec2 uv ) { return 1e-7 + 256. + dot(uv,k); }
float rnd2( vec2 uv ) { return mod( 123456789., 256. * dot(uv,k) ); }
float rnd3( vec2 uv ) { return cos( mod( 123456789., 256. * dot(uv,k) ) ); }

// We can even tweak the formula
float rnd4( vec2 uv ) { return fract( cos( mod( 1234., 1024. * dot(uv,k) ) ) ); }
float rnd5( vec2 uv ) { return fract( cos( mod( 12345., 1024. * dot(uv,k) ) ) ); }
float rnd6( vec2 uv ) { return fract( cos( mod( 123456., 1024. * dot(uv,k) ) ) ); }
float rnd7( vec2 uv ) { return fract( cos( mod( 1234567., 1024. * dot(uv,k) ) ) ); }
float rnd8( vec2 uv ) { return fract( cos( mod( 12345678., 1024. * dot(uv,k) ) ) ); }
float rnd9( vec2 uv ) { return fract( cos( mod( 123456780., 1024. * dot(uv,k) ) ) ); }

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    mediump vec2 uv = fragCoord.xy / iResolution.xy;
    float i = rnd9(uv);
    fragColor = vec4(i,i,i,1.);
}

上記をに貼り付けます:

また、2つのノイズ関数と2つのランダム関数を使用した「比較」ShaderToyの例を作成しました。

ノイズ使用デモ「[2TC15]スペックルクロスフェード」

snoise3「古典的な」ランダム関数は、この悪い関数と呼ばれることもあります。

return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);

「疑似ランダム」関数を比較したい場合は、サインシェーダーなしのDave'sHashをチェックしてください。

于 2012-05-16T19:52:02.607 に答える
8

ピクセル シェーダーでランダムな値が必要な場合に通常行うことは、ノイズを含むテクスチャを渡すことです。実際には「ランダム」ではありませんが、ランダムに見えます。

たとえば、私が横たわっているピクセルシェーダーのコードを次に示します。

float3 random = (tex2D(noiseTexture, texCoord * noiseScale + noiseOffset));

私が使用するテクスチャは RGB ノイズ テクスチャで、これは便利な場合があります。ただし、グレースケールの場合でも同じ手法が機能します。

それをスケーリングすることで、ノイズ テクスチャのピクセルが画面上のピクセルと一致するようにします (ノイズ テクスチャがぼやけないように、テクスチャ サンプラーを「ポイント」モードに設定することもできます)。

オフセットを使用すると、テクスチャをスクロールできます。これは、乱数ジェネレーターをシードするようなものです。その「スクロール」の外観を避けたい場合は、ランダムなオフセットを使用してください。

于 2011-03-01T03:34:04.527 に答える
6

乱数発生器のシードを実行ごとに再利用する必要があるということは何もありません。シードが必要なだけです。

たとえば、ピクセル座標を使用すると、決定論的な結果が得られます (つまり、ピクセル x、y には常に同じランダム フレアが適用されます) が、顔全体ではランダムに分散されます。

ここで、環境に基づいて変化する何かを入力として利用できる場合 (ピクセル シェーダーについては何も知りません)、たとえば、シーン/カメラの組み合わせのグローバル スペース内のピクセルの全体的な配置など、ポリゴンとの相対的な配置などです。特に動きの速い環境では、結果は効果的にランダムになります。

グローバル環境のすべてがたまたままったく同じである場合、はい、まったく同じ「ランダム」分布になります。しかし、これらの要因のいずれかが変化した場合 (特に、最も動的な「ノイズ源」である可能性が高いユーザー入力に基づいて)、全体的な効果はおそらく「十分にランダム」になります。

したがって、重要なことは、シードが乱数ジェネレーターの以前の実行の結果である必要はないということです。それは何でもかまいません。そのため、独自の RNG へのシェーダーへの入力に基づいて各ピクセルのシードを作成すると、必要な効果が得られる場合があります。

于 2011-03-01T01:38:47.670 に答える