考虑下面的简单着色器(前往 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()
则不然。
是否可以使用一些数学方法从 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/