OpenGL Pixel Shader:如何生成0和1的随机矩阵(在每个像素上)?

时间:2011-06-07 17:35:04

标签: opengl glsl shader pixel-shader pixel-bender

所以我需要的是简单:每次我们执行着色器(意味着每个像素)时,我需要计算1 s和0 s的随机矩阵resolution == originalImageResolution。怎么办这样的事情?

至于现在我已经为shadertoy创建了一个随机矩阵分辨率,这里设置为15乘15,因为当我尝试像200到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用于我现在所做的相同目的但是如果失败并且如果可能更快?

更新 我想要创建的是Single-Pixel Camera(谷歌压缩成像或压缩感知),我想创建基于gpu的软件实现。

想法很简单:

  • 我们有一张图片 - NxM
  • 对于图像中的每个像素,我们希望GPU执行下一个操作:
    • 生成NxM随机值矩阵 - 0 s和1 s。
    • 计算原始图像上所有像素的arithmetic mean,其坐标对应于随机1矩阵中NxM s的坐标
    • 算术平均值的输出结果作为像素颜色。

我试图在着色器中实现的是模拟那个谨慎的过程。

尝试在gpu上执行此操作真是愚蠢:

  • 压缩感知并不会让我们计算出这些算术平均值的NxM矩阵,它只是它的和平(例如1/3)。所以我在GPU上施加了一些我不需要的压力。然而,测试更多数据并不总是一个坏主意。

1 个答案:

答案 0 :(得分:2)

感谢您添加更多详细信息以澄清您的问题。我的评论太长了,所以我要回答。将评论移到这里以使它们保持在一起:

抱歉要慢,但我想了解问题和目标。在你的GLSL样本中,我没有看到生成矩阵。我看到通过对来自15×15纹理(矩阵)的细胞的随机选择(随时间变化)求和来生成单个vec3。并且为每个像素重新计算vec3。然后将vec3用作像素颜色。

所以我不清楚你是否真的想要创建一个矩阵,或者只是想为每个像素计算一个值。后者在某种意义上是一个“矩阵”,但计算一个200 x 200像素的简单随机值不会对你的图形驱动程序造成压力。你还说要使用矩阵。所以我认为这不是你的意思。

我试图理解为什么你想要一个矩阵 - 为所有像素保持一致的随机基础?如果是这样,您可以预先计算随机纹理,或者使用与rand()中一致的伪随机函数,除非不使用时间。你清楚地知道这一点,所以我想我仍然不明白目标。为什么要为每个像素求和纹理中随机选择的单元格?

我相信你的着色器崩溃的原因是你的main()函数超出了它的时间限制 - 对于单个像素或整个像素集。每个像素调用rand() 40,000次(在200 * 200嵌套循环中)当然可以解释这一点! 如果您有200 x 200像素,并且每个调用sin()40k次,则每帧160,000,000次调用。糟糕的GPU!

我希望如果我们更好地理解目标,我们将能够推荐一种更有效的方法来获得你想要的效果。

<强>更新

(删除了这一部分,因为它是错误的。即使源矩阵中​​的许多细胞可能各自对结果的贡献小于视觉上可检测的颜色量,但是许多细胞的总数可以提供视觉上可检测的颜色量。 。)

基于更新问题的新更新

好的,(在这里大声思考,这样你就可以检查我是否正确理解......)因为你只需要每个随机NxM值一次,所以没有实际要求将它们存储在一个矩阵中;这些值可以简单地按需计算,然后扔掉。这就是为什么上面的示例代码实际上不会生成矩阵。

这意味着我们无法摆脱每帧生成(NxM)^ 2个随机值,即每个像素的NxM随机值,并且存在NxM个像素。因此,对于N = M = 200,每帧有1.6亿个随机值。

然而,我们仍然可以优化一些东西。

  • 首先,由于您的随机值每个只需要一位(您只需要一个布尔答案来决定是否将每个单元格从源纹理包含到混合中),您可以使用更便宜的伪随机数生成器。你正在使用的那个输出每次调用输出的随机数据比一位多。例如,您可以调用与您现在使用的相同的PRNG函数,但是存储该值并从中提取32个随机位。或者至少有几个,取决于有多少是随机的。另外,如果你有扩展名GL_EXT_gpu_shader4(对于按位运算符),你可以使用something like this代替使用sin()函数:

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.0)执行一个除法运算,这可能相对昂贵,除非编译器和GPU能够将其优化为位移(可能是浮点数) ?)。这也不会给出输入值的算术平均值,如上所述......它将更加重视后面的值,而对前面的值则很少。作为一个解决方案,保持计算包含的值的数量,并在循环结束后除以该计数一次。

这些优化是否足以使您的GPU驱动程序能够每帧驱动200x200 * 200x200像素,我不知道。它们绝对可以让您大幅提高分辨率。

这些是我头脑中发生的想法。我不是一名GPU专家。如果有资格的人可以提出建议,那就太好了。

P.S。在你的评论中,你开玩笑地(?)提到了预先计算N * M NxM随机矩阵的选项。也许这不是一个坏主意? 40,000x40,000是一个很大的纹理(至少40MB),但如果你每个单元存储32位随机数据​​,那么它可以达到1250 x 40,000个单元。太糟糕的vanilla GLSL无法帮助您使用按位运算符来提取数据,但即使您没有GL_EXT_gpu_shader4扩展名,您仍然可以伪造它。 (也许你还需要一个特殊的扩展然后非方形纹理?)