glsl - 使用 smoothstep() 和 dot() 或 length() 绘制圆会产生不同的结果

标签 glsl shader smoothstep

考虑下面的简单着色器(前往 shadertoy.com/new 并粘贴代码进行尝试)。

基本上,我试图弄清楚是否可以调整 dot() 版本以获得这两个函数调用的完全相同的结果:

smoothstep( 0.0, r * r, dot(d, d) )
smoothstep( 0.0, r,     length(d) )

使用两种众所周知的方法绘制两个圆圈。通过阅读网上的教程,您了解到可以使用 length() 函数来绘制圆。您还了解到它相当昂贵,因此提供了一个更优化的版本,其中使用了 dot() 函数。 (在我的世界中,某些东西的优化版本应该产生相同的结果。)

太棒了。但我找不到两者之间关系的解释。有时,出于某种原因,dot() 的结果会乘以 4.0(请参阅 Book of Shaders ),给出类似但不相同的输出。

如您所见,step() 产生相同的圆,而 smoothstep() 则不然。

Typical GLSL circles :)

是否可以使用一些数学方法从 smoothstep() 获得完全相同的输出?

着色器示例

float circle_using_length(vec2 position, float radius) {
    vec2 d = position - vec2(0.5);
    return 1.0 - step(radius, length(d));
}

float circle_using_dot(in vec2 position, in float radius) {
    vec2 d = position - vec2(0.5);
    return 1.0 - step(radius * radius, dot(d, d));
}

float smooth_circle_using_length(vec2 position, float radius) {
    vec2 d = position - vec2(0.5);
    return 1.0 - smoothstep(0.0, radius, length(d));
}

float smooth_circle_using_dot(in vec2 position, in float radius) {
    vec2 d = position - vec2(0.5);
    return 1.0 - smoothstep(0.0, radius * radius, dot(d, d) /* magic needed here */);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord/iResolution.x;
    
    vec3 col = vec3(0.0);
    col += circle_using_length(uv + vec2(0.4, 0.05), 0.05);
    col += smooth_circle_using_length(uv + vec2(0.4, 0.2), 0.1);
    
    col += circle_using_dot(uv + vec2(0.2, 0.05), 0.05);
    col += smooth_circle_using_dot(uv + vec2(0.2, 0.2), 0.1);
    
    fragColor = vec4(col,1.0);
}

最佳答案

smoothstep(0.0, radius, length(d));

返回结果与

相同
smoothstep(0.0, radius, sqrt(dot(d, d)));

但是不等于

smoothstep(0.0, radius * radius, dot(d, d));

也就是说,因为 smoothstep 不是线性函数,因此 smoothstep(0, a, b) 不等于 smoothstep(0, a*a, b*b).

参见smoothstep :

t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);

(a*a - 0)/(b*b - 0) 不等于 (a - 0)/(b - 0)

关于glsl - 使用 smoothstep() 和 dot() 或 length() 绘制圆会产生不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70537724/

相关文章:

opengl-es - gl_FragData[0] 总是颜色缓冲区吗?

c++ - 着色器透明度不适用于一半

opengl - 为什么这个 glsl 着色器在尝试使用该程序时会导致 "Invalid Operation"?

opengl - OpenGL 二进制程序格式是否标准化?

c++ - 在细胞中产生噪声 - CPP 和 GLSL

c++ - 平滑步函数

opengl - Raymarching 夹紧坐标会产生奇怪的拉伸(stretch)伪像

c++ - Shader编译失败后能否调用glShaderSource更新Shader源码?

math - 对于平滑步长函数 glsl,edge0 大于或等于 edge1 是什么情况