Glsl WebGL:循环索引不能与非常量表达式进行比较

Glsl WebGL:循环索引不能与非常量表达式进行比较,glsl,webgl,Glsl,Webgl,我有一个webgl模糊着色器: precision mediump float; precision mediump int; uniform sampler2D u_image; uniform float blur; uniform int u_horizontalpass; // 0 or 1 to indicate vertical or horizontal pass uniform float sigma; // The sigma value for

我有一个webgl模糊着色器:

precision mediump float;
precision mediump int;

uniform sampler2D u_image;
uniform float blur;       
uniform int u_horizontalpass; // 0 or 1 to indicate vertical or horizontal pass
uniform float sigma;        // The sigma value for the gaussian function: higher value means more blur
                            // A good value for 9x9 is around 3 to 5
                            // A good value for 7x7 is around 2.5 to 4
                            // A good value for 5x5 is around 2 to 3.5
                            // ... play around with this based on what you need :)

varying vec4 v_texCoord;

const vec2 texOffset = vec2(1.0, 1.0);
// uniform vec2 texOffset;
const float PI = 3.14159265;

void main() {  
  vec2 p = v_texCoord.st;
  float numBlurPixelsPerSide = blur / 2.0; 

  // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
  vec3 incrementalGaussian;
  incrementalGaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
  incrementalGaussian.y = exp(-0.5 / (sigma * sigma));
  incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;

  vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
  float coefficientSum = 0.0;

  // Take the central sample first...
  avgValue += texture2D(u_image, p) * incrementalGaussian.x;
  coefficientSum += incrementalGaussian.x;
  incrementalGaussian.xy *= incrementalGaussian.yz;

  // Go through the remaining 8 vertical samples (4 on each side of the center)
  for (float i = 1.0; i <= numBlurPixelsPerSide; i += 1.0) { 
    avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;         
    avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;         
    coefficientSum += 2.0 * incrementalGaussian.x;
    incrementalGaussian.xy *= incrementalGaussian.yz;
  }

  gl_FragColor = avgValue / coefficientSum;
}
precision mediump float;
精密中泵;
均匀采样二维u_图像;
均匀浮动模糊;
均匀国际水平通行证;//0或1表示垂直或水平通道
均匀浮点西格玛;//高斯函数的sigma值:值越高表示模糊程度越高
//9x9的良好值约为3到5
//7x7的良好值约为2.5到4
//5x5的良好值约为2到3.5
// ... 根据您的需要来处理此问题:)
可变vec4 v_texCoord;
常数vec2 texOffset=vec2(1.0,1.0);
//均匀vec2-texOffset;
常数浮点PI=3.14159265;
void main(){
vec2 p=v_texCoord.st;
float numBlurPixelsPerSide=blur/2.0;
//增量高斯系数计算(见GPU Gems 3第877-889页)
vec3递增阿尔高辛;
增量algaussian.x=1.0/(sqrt(2.0*PI)*σ);
增量algaussian.y=exp(-0.5/(西格玛*西格玛));
incrementalGaussian.z=incrementalGaussian.y*incrementalGaussian.y;
vec4 avgValue=vec4(0.0,0.0,0.0,0.0);
浮动系数总和=0.0;
//先取中心样本。。。
avgValue+=纹理2D(u_图像,p)*增量algaussian.x;
coefficientSum+=增量algaussian.x;
incrementalGaussian.xy*=incrementalGaussian.yz;
//检查剩余的8个垂直样本(中心每侧4个)

对于(float i=1.0;i请尝试以下操作:

const float MAX_ITERATIONS = 100.0;

// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= MAX_ITERATIONS; i += 1.0) { 
    if (i >= numBlurPixelsPerSide){break;}
    avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;         
    avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;         
    coefficientSum += 2.0 * incrementalGaussian.x;
    incrementalGaussian.xy *= incrementalGaussian.yz;
}
var SCALE_FACTORS = [4, 8, 16, 32],
    shaderCode, // the code of my shader
    shaderPrograms = SCALE_FACTORS.map(function (factor) {
        var codeWithDefines = insertDefines(shaderCode, { SCALE_FACTOR: factor });
        /* compile shaders, link program, return */
    });
#extension GL_EXT_gpu_shader5 : require
const float MAX_迭代次数=100.0;
//检查剩余的8个垂直样本(中心每侧4个)
对于(float i=1.0;i=numBlurPixelsPerSide){break;}
avgValue+=纹理2D(u_图像,p-i*texOffset)*增量algaussian.x;
avgValue+=纹理2D(u_图像,p+i*texOffset)*增量algaussian.x;
系数总和+=2.0*增量阿尔高斯指数x;
incrementalGaussian.xy*=incrementalGaussian.yz;
}

我对图像下采样着色器也有类似的问题。代码基本相同:

for (int dx = -2 * SCALE_FACTOR; dx < 2 * SCALE_FACTOR; dx += 2) {
    for (int dy = -2 * SCALE_FACTOR; dy < 2 * SCALE_FACTOR; dy += 2) {
        /* accumulate fragment's color */
    }
}
实现有点棘手,因为如果代码中已经有
#version
预处理器语句,那么所有其他语句都必须遵循它

然后,我添加了一个正在定义的
SCALE\u FACROR
检查:

#ifndef SCALE_FACTOR
#   error SCALE_FACTOR is undefined
#endif
在我的javascript代码中,我做了如下操作:

const float MAX_ITERATIONS = 100.0;

// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= MAX_ITERATIONS; i += 1.0) { 
    if (i >= numBlurPixelsPerSide){break;}
    avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;         
    avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;         
    coefficientSum += 2.0 * incrementalGaussian.x;
    incrementalGaussian.xy *= incrementalGaussian.yz;
}
var SCALE_FACTORS = [4, 8, 16, 32],
    shaderCode, // the code of my shader
    shaderPrograms = SCALE_FACTORS.map(function (factor) {
        var codeWithDefines = insertDefines(shaderCode, { SCALE_FACTOR: factor });
        /* compile shaders, link program, return */
    });
#extension GL_EXT_gpu_shader5 : require

这是因为在某些硬件上,GLSL循环被取消卷积到本机GPU指令中。这意味着通过
for
循环的次数需要有一个硬上限,该上限控制将生成循环内部代码的多少个副本。如果用
常量fl替换
numBlurPixelsPerSide
oat
甚至是一个
#define
指令,着色器编译器可以在编译时确定传递次数,并相应地生成代码

这条规则中有一个有趣的问题:允许你在<<代码> > <代码>循环中,从代码< >代码>破解> <代码>返回< /代码>,即使在编译时必须识别最大迭代。例如,考虑。这不是GLSL沙盒上最漂亮的分形,但我选择它的小尺寸:

precision mediump float;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
varying vec2 surfacePosition;

const float max_its = 100.;

float mandelbrot(vec2 z){
    vec2 c = z;
    for(float i=0.;i<max_its;i++){     // for loop is here.
        if(dot(z,z)>4.) return i;      // conditional early return here.
        z = vec2(z.x*z.x-z.y*z.y,2.*z.x*z.y)+c;
    }
    return max_its;
}


void main( void ) {
    vec2 p = surfacePosition;
    gl_FragColor = vec4(mandelbrot(p)/max_its);
}
precision mediump float;
均匀浮动时间;
均匀vec2小鼠;
均匀vec2分辨率;
可变vec2表面沉积;
常量浮点最大值=100。;
浮动曼德尔布罗特(vec2 z){
vec2c=z;
for(float i=0;i4.)返回i;//此处有条件提前返回。
z=vec2(z.x*z.x-z.y*z.y,2.*z.x*z.y)+c;
}
返回最大值;
}
真空总管(真空){
Vec2p=表面沉积;
gl_FragColor=vec4(mandelbrot(p)/max_-its);
}
在本例中,
max_its
是一个
const
,因此编译器知道上限,如果需要,可以取消循环。在循环内部,一个
return
语句提供了一种方法,可以为Mandelbrot集合之外的像素提前退出循环


您仍然不希望将最大迭代次数设置得太高,因为这会产生大量GPU指令,可能会影响性能。

我在android上使用opengl es3,并通过在程序开头使用扩展来解决此问题,如下所示:

const float MAX_ITERATIONS = 100.0;

// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= MAX_ITERATIONS; i += 1.0) { 
    if (i >= numBlurPixelsPerSide){break;}
    avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;         
    avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;         
    coefficientSum += 2.0 * incrementalGaussian.x;
    incrementalGaussian.xy *= incrementalGaussian.yz;
}
var SCALE_FACTORS = [4, 8, 16, 32],
    shaderCode, // the code of my shader
    shaderPrograms = SCALE_FACTORS.map(function (factor) {
        var codeWithDefines = insertDefines(shaderCode, { SCALE_FACTOR: factor });
        /* compile shaders, link program, return */
    });
#extension GL_EXT_gpu_shader5 : require
我不知道它是否适用于webGL,但你可以试试。
希望它能有所帮助。

你可以用大常数做一个for循环,然后用一个break

for(int i = 0; i < 1000000; ++i) 
{ 
    // your code here
    if(i >= n){
        break;
    }
}
for(int i=0;i<1000000;++i)
{ 
//你的代码在这里
如果(i>=n){
打破
}
}

有时您可以使用我的非常简单的问题解决方案

着色器源代码的我的片段:

const int cloudPointsWidth = %s;
for ( int i = 0; i < cloudPointsWidth; i++ ) {
   //TO DO something
}
vertexCode
是我的着色器源代码

每次如果我想更改
cloudPointsWidth
,我都会销毁我的旧着色器,并使用新的
cloudPointsWidth
创建新着色器


希望有时我的解决方案能对您有所帮助。

您也可以使用template Literals来设置循环的长度

onBeforeCompile(shader) {
  const array = [1,2,3,4,5];
  shader.uniforms.myArray = { value: array };

  let token = "#include <begin_vertex>";
  const insert = `
    uniform float myArray[${array.length}];
    for ( int i = 0; i < ${array.length}; i++ ) {
       float test = myArray[ i ];
    }
  `;
  shader.vertexShader = shader.vertexShader.replace(token, token + insert);
}
onbeforecomile(着色器){
常量数组=[1,2,3,4,5];
shader.uniforms.myArray={value:array};
让token=“#include”;
常量插入=`
统一浮点myArray[${array.length}];
对于(int i=0;i<${array.length};i++){
浮动测试=myArray[i];
}
`;
shader.vertexShader=shader.vertexShader.replace(标记,标记+插入);
}

Simple and brilliant。这可能类似于jshint ignore:startclever,但没有公认的解决方案那么优雅