4

したがって、必要なのは単純です。シェーダーを実行するたびに(各ピクセルを意味します)、1sと0sのランダム行列を。で計算する必要がありresolution == originalImageResolutionます。そのようなことをどのように行うのですか?

今のところ、shadertoy用に1つ作成しました。ランダム行列の解像度はここで15 x 15に設定されています。これは、200 x 200のようなものを試してみると、GPUによってクロムが頻繁に落ちるためですが、実際には完全な画像解像度サイズが必要です。

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 resolution;
uniform float time;
uniform sampler2D tex0;

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * (43758.5453+ time));
}
vec3 getOne(){
    vec2 p =  gl_FragCoord.xy / resolution.xy;
    vec3 one;
    for(int i=0;i<15;i++){
        for(int j=0;j<15;j++){
            if(rand(p)<=0.5)
                one = (one.xyz + texture2D(tex0,vec2(j,i)).xyz)/2.0;
        }
    }
    return one;
}

void main(void)
{
    gl_FragColor = vec4(getOne(),1.0);
}

そして、Adobeピクセルベンダー用のもの:

<languageVersion: 1.0;> 

kernel random
<   namespace : "Random";
    vendor : "Kabumbus";
    version : 3;
    description : "not as random as needed, not as fast as needed"; >
{

    input image4 src;
    output float4 outputColor;

float rand(float2 co, float2 co2){
    return fract(sin(dot(co.xy ,float2(12.9898,78.233))) * (43758.5453 + (co2.x + co2.y )));
}

float4 getOne(){
    float4 one;
    float2 r = outCoord();
    for(int i=0;i<200;i++){
        for(int j=0;j<200;j++){
            if(rand(r, float2(i,j))>=1.0)
                one = (one + sampleLinear(src,float2(j,i)))/2.0;
        }
    }
    return one;
}
void
evaluatePixel()
{
    float4 oc = getOne();
    outputColor = oc;
}
}

だから私の本当の問題は-私のシェーダーが私のGPUダイバーを落とすということです。私が今しているのと同じ目的でGLSLを使用する方法はありますが、失敗することなく、可能であればより速くなりますか?

更新: 私が作成したいのはシングルピクセルカメラ(google CompressiveImagingまたはCompressiveSensing)と呼ばれ、GPUベースのソフトウェア実装を作成したいと思います。

アイデアは単純です:

  • 画像があります- NxM
  • 画像のピクセルごとに、GPUに次の操作を実行させます。
    • NxMランダムな値の行列を生成する0-sと1s。
    • 座標がランダム行列のsの座標に対応する元の画像上のすべてのピクセルの算術平均を計算します1NxM
    • 算術平均の出力結果をピクセルカラーとして出力します。

シェーダーに実装しようとしたのは、その慎重なプロセスをシミュレートすることでした。

GPUでこれを行おうとすると本当に愚かなことは何ですか?

  • 圧縮センシングはNxM、そのような算術平均値の行列を計算するために私たちに背を向けることはありません、それはそれの平和を単に意味します(例えば1/3)。そのため、GPUに必要のないプレッシャーをかけました。ただし、より多くのデータでテストすることは必ずしも悪い考えではありません。
4

1 に答える 1

2

質問を明確にするために詳細を追加していただきありがとうございます。コメントが長くなってしまいましたので、回答させていただきます。コメントをここに移動してまとめます:

遅くて申し訳ありませんが、問題と目標を理解しようとしています。あなたの GLSL サンプルでは、​​マトリックスが生成されていません。15 x 15 のテクスチャ (マトリックス) からランダムに選択された (時間の経過と共に変化する) セルを合計することによって、単一の vec3 が生成されているのがわかります。そして、その vec3 はピクセルごとに再計算されます。次に、vec3 がピクセルの色として使用されます。

そのため、本当にマトリックスを作成したいのか、それともすべてのピクセルの値を計算したいだけなのかはわかりません。後者はある意味で「マトリックス」ですが、200 x 200 ピクセルの単純なランダム値を計算しても、グラフィックス ドライバーに負荷がかかりません。また、マトリックスを使用したいと言いました。だから私はそれがあなたの言いたいことではないと思います。

なぜマトリックスが必要なのかを理解しようとしています-すべてのピクセルに対して一貫したランダムな基準を維持するためですか? その場合は、ランダム テクスチャを事前計算するか、時間を使用しないことを除いて rand() のような一貫した疑似乱数関数を使用できます。あなたはそれについてはっきりと知っているので、私はまだ目標を理解していないと思います. ピクセルごとに、テクスチャからランダムに選択したセルを合計するのはなぜですか?

シェーダーがクラッシュしている理由は、main()関数が時間制限を超えているためだと思います-単一のピクセルまたはピクセルのセット全体のいずれかです。rand()1 ピクセルあたり 40,000 回 (200 * 200 のネストされたループで)呼び出すと、確かにそれを説明できます! 200 x 200 ピクセルがあり、sin() をそれぞれ 4 万回呼び出すと、フレームごとに 160,000,000 回の呼び出しになります。GPUが悪い!

目標をよりよく理解できれば、希望する効果を得るためのより効率的な方法を推奨できるようになることを願っています.

アップデート。

(この部分は間違っていたので削除しました。ソース マトリックス内の多くのセルが結果に寄与する色の量が視覚的に検出できる量に満たない場合でも、多くのセルの合計は視覚的に検出できる量の色に寄与する可能性があります。)

更新された質問に基づく新しい更新。

OK、(ここで「大声で」考えて、私が正しく理解しているかどうかを確認できるようにします...) ランダムな NxM 値はそれぞれ 1 回しか必要ないため、それらを行列に格納する実際の要件はありません。値は必要に応じて単純に計算され、その後破棄されます。そのため、上記のコード例は実際には行列を生成しません。

これは、フレームごとに (NxM)^2 のランダム値、つまりピクセルごとに NxM のランダム値を生成することから逃れられず、NxM のピクセルがあることを意味します。したがって、N=M=200 の場合、フレームごとに 1 億 6000 万のランダム値になります。

ただし、いくつかのことはまだ最適化できます。

  • まず、ランダム値はそれぞれ 1 ビットで十分なので (ソース テクスチャの各セルをミックスに含めるかどうかを決定するブール値の答えだけが必要です)、安価な疑似乱数ジェネレーターを使用できる可能性があります。使用しているものは、呼び出しごとに 1 ビットよりもはるかに多くのランダム データを出力します。たとえば、現在使用しているのと同じ PRNG 関数を呼び出すことができますが、値を格納し、そこから 32 のランダム ビットを抽出します。または、十分にランダムな数に応じて、少なくともいくつか。さらに、sin() 関数を使用する代わりに、拡張機能 GL_EXT_gpu_shader4 (ビット演算子用) がある場合は、次のようなものを使用できます。

.

int LFSR_Rand_Gen(in int n)
{
  // <<, ^ and & require GL_EXT_gpu_shader4.
  n = (n << 13) ^ n;
  return (n * (n*n*15731+789221) + 1376312589) & 0x7fffffff;
}
  • 第 2 に、現在、含まれているセル ( ) ごとに 1 つの除算操作を実行しています/2.0。これは、コンパイラと GPU がビット シフトに最適化できない限り、おそらく比較的高価です (浮動小数点で可能ですか?)。上記のように、これは入力値の算術平均も与えません...それは後の値にはるかに多くの重みを置き、前の値にはほとんど重みを置きません。解決策として、含まれている値の数を数え、ループが終了した後にその数で 1 回割ります。

これらの最適化が、GPU ドライバーがフレームあたり 200x200 * 200x200 ピクセルを駆動できるようにするのに十分かどうかはわかりません。解像度を大幅に向上させることができるはずです。

これらは、頭のてっぺんから私に思い浮かぶアイデアです。ただし、私は GPU の専門家にはほど遠いです。より有能な人が提案でチャイムを鳴らすことができれば、それは素晴らしいことです.

PS あなたのコメントでは、冗談めかして (?) N*M NxM ランダム行列を事前計算するオプションについて言及しました。多分それは悪い考えではありませんか?? 40,000x40,000 は大きなテクスチャ (少なくとも 40MB) ですが、セルごとに 32 ビットのランダム データを保存すると、1250 x 40,000 セルになります。残念なことに、バニラ GLSL はビット単位の演算子を使用してデータを抽出するのに役立ちませんが、GL_EXT_gpu_shader4 拡張機能がなくても偽造することができます。(おそらく、非正方形のテクスチャの場合は特別な拡張機能も必要になるでしょうか?)

于 2011-06-08T14:55:48.633 に答える