3

私はProcessingで少しおかしなことを書きましたが、これをMacOSXスクリーンセーバーにしたいと思います。しかし、OpenGLに飛び込むのは、思ったほど簡単ではありませんでした。

基本的に、画面上のすべてのピクセルをループし、そのピクセルの色に基づいて別のピクセルの色を設定します。

処理コードは次のようになります。

void setup(){
  size(500,500, P2D);
  frameRate(30);
  background(255);
}

void draw(){
 for(int x = 0; x<width; x++){
  for(int y = 0; y<height; y++){
     float xRand2 = x+random(2);
     float yRand2 = y+random(2);

     int xRand = int(xRand2);
     int yRand = int(yRand2);

     if(get(x,y) == -16777216){
     set(x+xRand, y+yRand, #FFFFFF);
     }
     else if(get(x,y) == -1){
     set(x+xRand, y+yRand, #000000);
     }
   }
 }
}

それはあまりきれいではなく、また非常に効果的でもありません。ただし、OpenGLで同様のことを行う方法を知りたいと思います。どこから始めればいいのかわからない。

4

3 に答える 3

2

OpenGLの基本的な考え方は、個々のピクセルの値を手動で設定することは決してないということです。これは、速度が遅すぎることが多いためです。代わりに、三角形をレンダリングし、テクスチャやブレンドなど、三角形を使ってあらゆる種類のトリックを実行します。

OpenGLで個々のピクセルが行うことを自由にプログラムするには、シェーダーと呼ばれる手法を使用する必要があります。そして、あなたが以前に同様のことをしたことがなければ、それは非常に簡単ではありません。シェーダーの考え方は、GPUがCPUの代わりにシェーダーを実行することです。これにより、非常に優れたパフォーマンスが得られ、CPUの負荷が軽減されます。ただし、あなたの場合は、シェーダーやOpenGLではなく、CPUを使用して実行する方がおそらく良いでしょう。そのアプローチは、開始するのがはるかに簡単だからです。

SDL(または場合によってはglfw)のようなライブラリを使用することをお勧めします。これにより、ハードウェアアクセラレーションなしでピクセルを使用して処理を実行できます。ただし、OpenGLでも実行できます。関数glDrawPixelsを使用する。この関数は、生のピクセルデータを画面に描画します。しかし、それはおそらくそれほど速くはありません。

たとえば、SDLに関するいくつかのチュートリアルを読むことから始めます。

編集:シェーダーを使用する場合、(とりわけ)シェーダーの難しさは、ピクセル値を設定する座標を指定できないことです。また、画面から直接ピクセル値を取得することもできません。シェーダーでそれを行う1つの方法は、次のとおりです。

  • テクスチャAテクスチャBの2つのテクスチャを設定します
  • テクスチャの1つを、すべてをレンダリングするターゲットとしてバインドします
  • 別のテクスチャをシェーダーの入力テクスチャとしてバインドします
  • シェーダーを使用してフルスクリーンの四角形をレンダリングし、結果を画面に表示します
  • テクスチャAとBを入れ替えて、前の結果を次の入力として使用するようになりました
  • もう一度レンダリング
于 2011-01-22T01:45:12.087 に答える
2

シェーダールートを使用したくない場合は、2DメモリアレイのCPUですべてのピクセル変更を行ってから、フレームごとにglDrawPixelsを使用してピクセルを画面にプッシュしてください。ハードウェアアクセラレーションはそれほど速くありませんが、目的には問題ない場合があります。もう1つの試みは、glTexImage2Dを使用して、フレームごとに新しいピクセルデータをテクスチャにバインドしてから、テクスチャクワッドを画面全体にレンダリングすることです。どちらが速くなるかわかりません。私のアドバイスは、シェーダーの複雑さに飛び込む前に、これらのことを試すことです。

于 2011-01-22T04:20:28.490 に答える
0

コードには、リバースエンジニアリングと移植を困難にするバグがいくつかあり、実際に正しいコードを投稿したかどうか疑問に思います。生成された視覚効果があなたが望むものであると仮定すると、ここにもっと効率的でより正しいものがありますdraw()

void draw() {
  loadPixels();
  for(int x = 0; x<width/2; x++) {
    for(int y = 0; y<height/2; y++) {
      int x_new = 2*x+int(random(2));
      int y_new = 2*y+int(random(2));

      if (x_new < width && y_new < height) {
        int dest_pixel = (y_new*width + x_new);

        color c = pixels[y*width+x];

        if(c == #FFFFFF){
          pixels[dest_pixel] = #000000;
        }
        else {
          pixels[dest_pixel] = #FFFFFF;
        }
      }
    }
  }
  updatePixels();
}

ループの上限は2で割られていることに注意してください。あなたが書いたように、あなたのset()呼び出しの3/4は、ウィンドウの境界を超えたピクセルに対するものでした。if座標に小さなランダムな値が追加されるため、追加が必要です。

このコードの全体的な効果は、画像のインプレースストレッチとインバートとして説明でき、少しランダムになります。インプレース変換であるため、簡単に並列化または加速することはできません。 CPUでビットマップ/テクスチャ操作としてこれを実装するのが最善です。GPUからピクセルを読み取ることなくこれを行うことができますが、フレームごとにピクセルでいっぱいの画面をGPUにプッシュする必要があります。

glDrawPixelsのformat引数GL_LUMINANCEとのtype引数を使用すると、GL_UNSIGNED_BYTEこのコードをバイト配列で動作するように非常に簡単に変換できます。これにより、32ビットRGBA値を使用する場合と比較してメモリ消費量をいくらか抑えることができます。

于 2011-01-22T07:17:47.330 に答える