WebGL 代码的解释 - 为什么它以这种方式工作
Explanation of WebGL code - why does it work that way
我正在尝试制作一个稍微发光然后变暗的灯泡。同样在边缘要稍微暗一点。我找到了一个代码,我认为它可以创建我想要创建的效果,但我似乎不太了解它。这是代码:
mat2 rotate2d(float angle){
return mat2(cos(angle),-sin(angle),
sin(angle),cos(angle));
}
float variation(vec2 v1, vec2 v2, float strength, float speed) {
return sin(
dot(normalize(v1), normalize(v2)) * strength + iGlobalTime * speed
) / 100.0;
}
vec3 paintCircle (vec2 uv, vec2 center, float rad, float width) {
vec2 diff = center-uv;
float len = length(diff);
len += variation(diff, vec2(0.0, 1.0), 5.0, 2.0);
len -= variation(diff, vec2(1.0, 0.0), 5.0, 2.0);
float circle = smoothstep(rad-width, rad, len) - smoothstep(rad, rad+width, len);
return vec3(circle);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
uv.x *= 1.5;
uv.x -= 0.25;
vec3 color;
float radius = 0.35;
vec2 center = vec2(0.5);
//paint color circle
color = paintCircle(uv, center, radius, 0.1);
//color with gradient
vec2 v = rotate2d(iGlobalTime) * uv;
color *= vec3(v.x, v.y, 0.7-v.y*v.x);
//paint white circle
color += paintCircle(uv, center, radius, 0.01);
fragColor = vec4(color, 1.0);
}
我不明白为什么我们需要归一化向量的点积以及它是如何精确选择的:
len += variation(diff, vec2(0.0, 1.0), 5.0, 2.0);
len -= variation(diff, vec2(1.0, 0.0), 5.0, 2.0);
我的意思是——为什么先加,再减?
那是为什么:
vec2 uv = fragCoord.xy / iResolution.xy;
uv.x *= 1.5;
uv.x -= 0.25;
这是怎么做到的
vec2 v = rotate2d(iGlobalTime) * uv;
color *= vec3(v.x, v.y, 0.7-v.y*v.x);
做颜色渐变?
如果有人喜欢在那里观看它以及它的作用,这里有一个 link 的代码:https://www.shadertoy.com/view/ltBXRc。
我显然不擅长几何。如果有人能帮助我,我将不胜感激:)
如果我们想画一个完美的圆,我们只需绘制距离场景中心一定距离的所有点。从程序上讲,我们会从中心开始,随机选择一个方向,在那个方向上走一段距离 r
,然后绘制一个点。然后 return 到中心,选择其他方向,走相同的距离 r
,然后绘制另一个点。依此类推,直到我们有一个平滑的圆:
r = 1
要绘制一个扭曲的圆,我们可以根据我们面对的方向改变距离 r
。如果我们将方向表示为以弧度为单位的角度 (theta
),那么 r
将是该角度的某个函数。具体什么功能?让我们先尝试一些简单的事情:r = theta
不是我们想要的安静,它应该更像一个圆(r = 1),但有点波浪(r = 1 + 波浪)。最简单的波浪函数是sin(x). Let's try to add it: r = 1 + 0.1 * sin(5 * theta)
通过改变数字,我们可以控制波的振幅和频率。但是对称性太多了,要打破它,我们需要比正弦波更复杂的东西。
这个怪物怎么样sin(5 * sin(x)) - sin(5 * cos(x))
加圈子吧r = 1 + 0.1 * sin(5 * sin(theta)) - 0.1 * sin(5 * cos(theta))
我觉得还不错。
着色器执行的正是这种变形,但方式不同。对标准基向量进行点积,即可得到向量的 X 或 Y 坐标。我们可以将该位重写为:
len += 0.02 * sin(normalize(diff).y * 5.0 + 2.0 * iGlobalTime);
len -= 0.02 * sin(normalize(diff).x * 5.0 + 2.0 * iGlobalTime);
归一化向量的 X 和 Y 坐标只是该向量表示的角度的 sin
和 cos
。因此,normalize(diff).y
给出角度的正弦值,normalize(diff).x
给出余弦值。
希望这能让事情变得更清楚一些。
我正在尝试制作一个稍微发光然后变暗的灯泡。同样在边缘要稍微暗一点。我找到了一个代码,我认为它可以创建我想要创建的效果,但我似乎不太了解它。这是代码:
mat2 rotate2d(float angle){
return mat2(cos(angle),-sin(angle),
sin(angle),cos(angle));
}
float variation(vec2 v1, vec2 v2, float strength, float speed) {
return sin(
dot(normalize(v1), normalize(v2)) * strength + iGlobalTime * speed
) / 100.0;
}
vec3 paintCircle (vec2 uv, vec2 center, float rad, float width) {
vec2 diff = center-uv;
float len = length(diff);
len += variation(diff, vec2(0.0, 1.0), 5.0, 2.0);
len -= variation(diff, vec2(1.0, 0.0), 5.0, 2.0);
float circle = smoothstep(rad-width, rad, len) - smoothstep(rad, rad+width, len);
return vec3(circle);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
uv.x *= 1.5;
uv.x -= 0.25;
vec3 color;
float radius = 0.35;
vec2 center = vec2(0.5);
//paint color circle
color = paintCircle(uv, center, radius, 0.1);
//color with gradient
vec2 v = rotate2d(iGlobalTime) * uv;
color *= vec3(v.x, v.y, 0.7-v.y*v.x);
//paint white circle
color += paintCircle(uv, center, radius, 0.01);
fragColor = vec4(color, 1.0);
}
我不明白为什么我们需要归一化向量的点积以及它是如何精确选择的:
len += variation(diff, vec2(0.0, 1.0), 5.0, 2.0);
len -= variation(diff, vec2(1.0, 0.0), 5.0, 2.0);
我的意思是——为什么先加,再减? 那是为什么:
vec2 uv = fragCoord.xy / iResolution.xy;
uv.x *= 1.5;
uv.x -= 0.25;
这是怎么做到的
vec2 v = rotate2d(iGlobalTime) * uv;
color *= vec3(v.x, v.y, 0.7-v.y*v.x);
做颜色渐变? 如果有人喜欢在那里观看它以及它的作用,这里有一个 link 的代码:https://www.shadertoy.com/view/ltBXRc。 我显然不擅长几何。如果有人能帮助我,我将不胜感激:)
如果我们想画一个完美的圆,我们只需绘制距离场景中心一定距离的所有点。从程序上讲,我们会从中心开始,随机选择一个方向,在那个方向上走一段距离 r
,然后绘制一个点。然后 return 到中心,选择其他方向,走相同的距离 r
,然后绘制另一个点。依此类推,直到我们有一个平滑的圆:
r = 1
要绘制一个扭曲的圆,我们可以根据我们面对的方向改变距离 r
。如果我们将方向表示为以弧度为单位的角度 (theta
),那么 r
将是该角度的某个函数。具体什么功能?让我们先尝试一些简单的事情:r = theta
不是我们想要的安静,它应该更像一个圆(r = 1),但有点波浪(r = 1 + 波浪)。最简单的波浪函数是sin(x). Let's try to add it: r = 1 + 0.1 * sin(5 * theta)
通过改变数字,我们可以控制波的振幅和频率。但是对称性太多了,要打破它,我们需要比正弦波更复杂的东西。
这个怪物怎么样sin(5 * sin(x)) - sin(5 * cos(x))
加圈子吧r = 1 + 0.1 * sin(5 * sin(theta)) - 0.1 * sin(5 * cos(theta))
我觉得还不错。
着色器执行的正是这种变形,但方式不同。对标准基向量进行点积,即可得到向量的 X 或 Y 坐标。我们可以将该位重写为:
len += 0.02 * sin(normalize(diff).y * 5.0 + 2.0 * iGlobalTime);
len -= 0.02 * sin(normalize(diff).x * 5.0 + 2.0 * iGlobalTime);
归一化向量的 X 和 Y 坐标只是该向量表示的角度的 sin
和 cos
。因此,normalize(diff).y
给出角度的正弦值,normalize(diff).x
给出余弦值。
希望这能让事情变得更清楚一些。