基于世界的 GLSL 片段着色器 UV 置换 space
GLSL Fragment shader UV displacement based on world space
我正在尝试为网站上的图像创建 rgb 偏移效果。我有基本的功能,但问题是通道被纹理的 uv 偏移了。因此,如果图像大小不同,则每个图像的偏移量在视觉上并不相同。
这是我的片段着色器。
uniform sampler2D texture;
varying vec2 vUv; // vertex uv
void main() {
vec2 uv = vUv;
float red = texture2D(texture, vec2(uv.x, uv.y - .1)).r;
float green = texture2D(texture, uv).g;
float blue = texture2D(texture, vec2(uv.x, uv.y + .1)).b;
float alpha = texture2D(texture, uv).a;
gl_FragColor = vec4(vec3(red, green, blue), alpha);
}
以及它在页面上的呈现方式。
如何在不必传入统一值的情况下对 uv 偏移进行归一化?
如果您要使用 WebGL 2.0 context (see How to use WebGL2), then you can use textureSize
来获取纹理的大小。例如:
#version 300 es
uniform sampler2D tex;
in vec2 vUv;
out vec4 color;
void main() {
vec2 uv = vUv;
vec2 size = vec2(textureSize(tex, 0));
float pixel = 10.0;
float offset = pixel / size.y;
float red = texture(tex, vec2(uv.x, uv.y - offset)).r;
float green = texture(tex, uv).g;
float blue = texture(tex, vec2(uv.x, uv.y + offset)).b;
float alpha = texture(tex, uv).a;
color = vec4(red, green, blue, alpha);
}
请注意,您必须更改纹理采样器统一的名称
如果你需要知道你在屏幕-space(不是3D世界space)中的哪个像素,你可以使用gl_FragCoord
。例如,在 1080p 显示器中,gl_FragCoord.x
将从左侧的 0 开始,并增加到屏幕右侧的 1920。 gl_FragCoord.y
的范围比 [0, 1080] 短一点(由于 OS 菜单栏)。您可以像这样在片段着色器中提取这些坐标:
vec2 coord = gl_FragCoord.xy;
这样你就可以知道你在屏幕上的哪个像素 - space,而不必传递另一个制服。详情请看这里:
https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/gl_FragCoord.xhtml
传入偏移量等更多信息是正常的
uniform float offset1;
uniform float offset2;
uniform sampler2D texture;
varying vec2 vUv; // vertex uv
void main() {
vec2 uv = vUv;
float red = texture2D(texture, vec2(uv.x, uv.y + offset1)).r;
float green = texture2D(texture, uv).g;
float blue = texture2D(texture, vec2(uv.x, uv.y + offset2)).b;
float alpha = texture2D(texture, uv).a;
gl_FragColor = vec4(vec3(red, green, blue), alpha);
}
然后您可以在 JavaScript 中进行调整。例如
const uniforms = {
offset1: { value: 0 },
offset2: { value: 0 },
...
};
...
uniforms.offset1.value = 2 / textureHeight;
uniforms.offset2.value = -2 / textureHeight;
如果是我我可能会更像这样
uniform vec2 channelOffsets[4];
uniform vec4 channelMult[4];
uniform sampler2D texture;
varying vec2 vUv; // vertex uv
void main() {
vec2 uv = vUv;
vec4 channel0 = texture2D(texture, uv + channelOffset[0]);
vec4 channel1 = texture2D(texture, uv + channelOffset[1]);
vec4 channel2 = texture2D(texture, uv + channelOffset[2]);
vec4 channel3 = texture2D(texture, uv + channelOffset[3]);
gl_FragColor =
channelMult[0] * channel0 +
channelMult[1] * channel1 +
channelMult[2] * channel2 +
channelMult[3] * channel3 ;
}
并设置它们
const uniforms = {
channelOffsets: { value: [
new THREE.Vector2(),
new THREE.Vector2(),
new THREE.Vector2(),
new THREE.Vector2(),
]},
channelMults: { value: [
new THREE.Vector4(1, 0, 0, 0),
new THREE.Vector4(0, 1, 0, 0),
new THREE.Vector4(0, 0, 1, 0),
new THREE.Vector4(0, 0, 0, 1),
]},
....
}
...
uniforms.channelOffsets.value[0].y = -2 / textureHeight;
uniforms.channelOffsets.value[2].y = 2 / textureHeight;
举个不那么硬编码的例子。我什至可以使用纹理矩阵而不是偏移量,这将允许旋转和缩放每个通道并将它们与允许交换通道的矩阵组合。
我正在尝试为网站上的图像创建 rgb 偏移效果。我有基本的功能,但问题是通道被纹理的 uv 偏移了。因此,如果图像大小不同,则每个图像的偏移量在视觉上并不相同。
这是我的片段着色器。
uniform sampler2D texture;
varying vec2 vUv; // vertex uv
void main() {
vec2 uv = vUv;
float red = texture2D(texture, vec2(uv.x, uv.y - .1)).r;
float green = texture2D(texture, uv).g;
float blue = texture2D(texture, vec2(uv.x, uv.y + .1)).b;
float alpha = texture2D(texture, uv).a;
gl_FragColor = vec4(vec3(red, green, blue), alpha);
}
以及它在页面上的呈现方式。
如何在不必传入统一值的情况下对 uv 偏移进行归一化?
如果您要使用 WebGL 2.0 context (see How to use WebGL2), then you can use textureSize
来获取纹理的大小。例如:
#version 300 es
uniform sampler2D tex;
in vec2 vUv;
out vec4 color;
void main() {
vec2 uv = vUv;
vec2 size = vec2(textureSize(tex, 0));
float pixel = 10.0;
float offset = pixel / size.y;
float red = texture(tex, vec2(uv.x, uv.y - offset)).r;
float green = texture(tex, uv).g;
float blue = texture(tex, vec2(uv.x, uv.y + offset)).b;
float alpha = texture(tex, uv).a;
color = vec4(red, green, blue, alpha);
}
请注意,您必须更改纹理采样器统一的名称
如果你需要知道你在屏幕-space(不是3D世界space)中的哪个像素,你可以使用gl_FragCoord
。例如,在 1080p 显示器中,gl_FragCoord.x
将从左侧的 0 开始,并增加到屏幕右侧的 1920。 gl_FragCoord.y
的范围比 [0, 1080] 短一点(由于 OS 菜单栏)。您可以像这样在片段着色器中提取这些坐标:
vec2 coord = gl_FragCoord.xy;
这样你就可以知道你在屏幕上的哪个像素 - space,而不必传递另一个制服。详情请看这里:
https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/gl_FragCoord.xhtml
传入偏移量等更多信息是正常的
uniform float offset1;
uniform float offset2;
uniform sampler2D texture;
varying vec2 vUv; // vertex uv
void main() {
vec2 uv = vUv;
float red = texture2D(texture, vec2(uv.x, uv.y + offset1)).r;
float green = texture2D(texture, uv).g;
float blue = texture2D(texture, vec2(uv.x, uv.y + offset2)).b;
float alpha = texture2D(texture, uv).a;
gl_FragColor = vec4(vec3(red, green, blue), alpha);
}
然后您可以在 JavaScript 中进行调整。例如
const uniforms = {
offset1: { value: 0 },
offset2: { value: 0 },
...
};
...
uniforms.offset1.value = 2 / textureHeight;
uniforms.offset2.value = -2 / textureHeight;
如果是我我可能会更像这样
uniform vec2 channelOffsets[4];
uniform vec4 channelMult[4];
uniform sampler2D texture;
varying vec2 vUv; // vertex uv
void main() {
vec2 uv = vUv;
vec4 channel0 = texture2D(texture, uv + channelOffset[0]);
vec4 channel1 = texture2D(texture, uv + channelOffset[1]);
vec4 channel2 = texture2D(texture, uv + channelOffset[2]);
vec4 channel3 = texture2D(texture, uv + channelOffset[3]);
gl_FragColor =
channelMult[0] * channel0 +
channelMult[1] * channel1 +
channelMult[2] * channel2 +
channelMult[3] * channel3 ;
}
并设置它们
const uniforms = {
channelOffsets: { value: [
new THREE.Vector2(),
new THREE.Vector2(),
new THREE.Vector2(),
new THREE.Vector2(),
]},
channelMults: { value: [
new THREE.Vector4(1, 0, 0, 0),
new THREE.Vector4(0, 1, 0, 0),
new THREE.Vector4(0, 0, 1, 0),
new THREE.Vector4(0, 0, 0, 1),
]},
....
}
...
uniforms.channelOffsets.value[0].y = -2 / textureHeight;
uniforms.channelOffsets.value[2].y = 2 / textureHeight;
举个不那么硬编码的例子。我什至可以使用纹理矩阵而不是偏移量,这将允许旋转和缩放每个通道并将它们与允许交换通道的矩阵组合。