3

我用 Processing 写了一些东西,现在我想制作一个 Mac OS X 屏幕保护程序。然而,深入研究 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

如果您不想走着色器路线,请尝试在 2D 内存阵列上的 CPU 中进行所有像素修改,然后每帧使用 glDrawPixels 将像素推送到屏幕上。它不会是非常硬件加速的,但它可能适合您的目的。要尝试的另一件事是使用 glTexImage2D 将每帧的新像素数据绑定到纹理,然后将纹理四边形渲染到整个屏幕。我不确定哪个会更快。我的建议是在进入着色器的复杂性之前尝试这些事情。

于 2011-01-22T04:20:28.490 回答
2

OpenGL 的基本思想是永远不要手动设置单个像素的值,因为这通常太慢了。相反,你渲染三角形并用它们做各种技巧,比如纹理、混合等。

为了自由编程每个像素在 OpenGL 中的作用,您需要使用一种称为着色器的技术。如果您以前没有做过类似的事情,这并不容易。着色器的想法是由 GPU 代替 CPU 执行它们,这会产生非常好的性能并减轻 CPU 的负载。但是在您的情况下,使用 CPU 而不是使用着色器和 OpenGL 可能是一个更好的主意,因为这种方法更容易开始。

我建议您使用像 SDL(或者可能是 glfw)这样的库,它可以让您在没有硬件加速的情况下处理像素。不过,您仍然可以使用 OpenGL 来做到这一点。通过使用函数 glDrawPixels。该函数将原始像素数据绘制到屏幕上。但这可能不是很快。

例如,首先阅读一些有关 SDL 的教程。

编辑:如果您想使用着色器,它们的困难(除其他外)是您无法指定设置像素值的坐标。而且您也不能直接从屏幕上获取像素值。使用着色器的一种方法如下:

  • 设置两个纹理:纹理 A纹理 B
  • 将其中一个纹理绑定为您渲染所有内容的目标
  • 将另一个纹理绑定为着色器的输入纹理
  • 使用着色器渲染全屏四边形并在屏幕上显示结果
  • 交换纹理 A 和 B,这样您就可以使用以前的结果作为下一个输入
  • 再次渲染
于 2011-01-22T01:45:12.087 回答
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();
}

请注意,循环的上限被二除。正如您所写的那样,您的set()调用中有 3/4 是针对超出窗口范围的像素。if由于向坐标添加了小的随机值,因此额外的值是必要的。

这段代码的整体效果可以描述为图像的原地拉伸和反转,加入了一点随机性。因为它是原地转换,它不能轻易并行化或加速,所以你最好将其实现为 CPU 上的位图/纹理操作。您可以做到这一点,而不必从 GPU 读取像素,但您必须每帧将一个充满像素的屏幕推送到 GPU。

如果您使用glDrawPixels的格式参数GL_LUMINANCE和 的类型参数GL_UNSIGNED_BYTE,那么您可以很容易地将此​​代码转换为对字节数组进行操作,与使用 32 位 RGBA 值相比,这将在一定程度上降低内存消耗。

于 2011-01-22T07:17:47.330 回答