我有一个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;
}
Run Code Online (Sandbox Code Playgroud)
当我构建时,我收到以下错误消息:
webgl-renderer.js?2eb3:137 Uncaught无法编译着色器:ERROR:0:38:'i':循环索引无法与非常量表达式进行比较
我也曾尝试使用刚刚统一的浮动模糊比较我来.有没有什么办法解决这一问题?
这个问题在这里进一步详述:https://www.khronos.org/webgl/public-mailing-list/archives/1012/msg00063.php
我发现的解决方案是在比较循环var时仅使用常量表达式.这不符合我需要做的事情,这取决于我根据模糊半径循环的次数.
有什么想法吗?
发生这种情况是因为在某些硬件上,GLSL循环被解压缩为本机GPU指令.这意味着通过for循环的次数需要有一个硬上限,它决定了循环内部代码的生成副本数量.如果替换numBlurPixelsPerSide为const float甚至是#define指令,则着色器编译器可以在编译时确定传递次数,并相应地生成代码.但是在那里有一个制服,在编译时不知道上限.
有此规则中一个有趣的皱纹:你被允许break或提前进行return了的for循环,即使最大的迭代必须辨别的编译时间.例如,考虑一下这个微小的Mandelbrot着色器.这不是GLSL Sandbox上最漂亮的分形,但我选择它的尺寸很小:
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);
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,max_its是一个const如此编译器知道上限并且如果需要可以解开这个循环.在循环内部,return语句提供了一种方法,可以提前为Mandelbrot集合之外的像素保留循环.
您仍然不希望将最大迭代次数设置得太高,因为这会产生大量GPU指令并可能损害性能.
尝试这样的事情:
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;
}
Run Code Online (Sandbox Code Playgroud)
有时您可以使用我非常简单的问题解决方案。
我的着色器源代码片段:
const int cloudPointsWidth = %s;
for ( int i = 0; i < cloudPointsWidth; i++ ) {
//TO DO something
}
Run Code Online (Sandbox Code Playgroud)
您可以在上面看到 '%' : 语法错误。但在使用着色器之前,我将 %s 替换为 javascript 代码中的数字。例如:
vertexCode = vertexCode.replace( '%s', 10 );
Run Code Online (Sandbox Code Playgroud)
vertexCode是我的着色器源代码。
每次如果我想改变cloudPointsWidth,我都会销毁旧的着色器并用新的着色器创建新的着色器cloudPointsWidth。
希望有时候我的解决可以帮助到你。
| 归档时间: |
|
| 查看次数: |
4638 次 |
| 最近记录: |