4

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

至于现在我已经创建了一个shadertoy随机矩阵分辨率在这里设置为15 x 15,因为当我尝试像200 x 200这样的东西时,gpu会使chrome经常下降,而我真的需要完整的图像分辨率大小

#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);
}

还有一个用于 Adob​​e 像素弯曲器:

<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 Compressive Imaging 或 Compressive Sensing),我想创建基于 gpu 的软件实现。

想法很简单:

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

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

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

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

1 回答 1

2

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

对不起,速度很慢,但我正在努力理解问题和目标。在您的 GLSL 示例中,我没有看到正在生成矩阵。我看到一个 vec3 是通过对 15 x 15 纹理(矩阵)中随机选择的单元格(随时间变化)求和而生成的。并且为每个像素重新计算 vec3。然后将 vec3 用作像素颜色。

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

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

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

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

更新。

(删除了这部分,因为它是错误的。即使源矩阵中​​的许多单元格对结果的贡献可能少于视觉可检测的颜色量,但许多单元的总和可以贡献视觉可检测的颜色量。)

基于更新问题的新更新。

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

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

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

  • 首先,由于您的随机值每个只需要一位(您只需要一个布尔答案来决定是否将源纹理中的每个单元格包含到混合中),您可能可以使用更便宜的伪随机数生成器。您使用的每次调用输出的随机数据比一位多得多。例如,您可以调用与您现在使用的相同的 PRNG 函数,但存储该值并从中提取 32 个随机位。或者至少有几个,取决于有多少足够随机。此外,如果您有扩展 GL_EXT_gpu_shader4(用于按位运算符),而不是使用 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 专家。如果更有资格的人能提出建议,那就太好了。

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

于 2011-06-08T14:55:48.633 回答