Three.js 基于世界空间的GLSL片段着色器UV置换

Three.js 基于世界空间的GLSL片段着色器UV置换,three.js,glsl,shader,fragment-shader,Three.js,Glsl,Shader,Fragment Shader,我正在尝试为网站上的图像创建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

我正在尝试为网站上的图像创建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偏移进行归一化?

如果要使用上下文查看,则可以使用获取纹理的大小。e、 g:

300版es 均匀采样2d-tex; 在vec2vuv中; 输出vec4颜色; 真空总管{ vec2-uv=vUv; vec2 size=vec2textureSizetex,0; 浮动像素=10.0; 浮动偏移=像素/大小.y; float red=texturetex,vec2uv.x,uv.y-offset.r; 浮动绿色=texturetex,uv.g; 浮动蓝色=texturetex,vec2uv.x,uv.y+偏移量.b; float alpha=texturetex,uv.a; 颜色=矢量4红色、绿色、蓝色、alpha; }
注意,您必须更改纹理采样器的名称。如果您需要知道在屏幕空间而不是3D世界空间中使用哪个像素,可以使用gl_FragCoord。例如,在1080p显示器中,gl_FragCoord.x将从左侧的0开始,在屏幕右侧增加到1920。由于操作系统菜单栏的原因,gl_FragCoord.y的范围将略短于[01080]。可以在片段着色器中提取这些坐标,如下所示:

vec2 coord = gl_FragCoord.xy;
这样,您就可以知道屏幕空间中的像素,而无需穿上另一件制服。有关更多详细信息,请参见此处:


传递更多信息(如偏移量)是正常的

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;


例如一些不太硬编码的东西。我甚至可以使用纹理矩阵而不是偏移,这样可以旋转和缩放每个通道,并将它们与允许交换通道的矩阵结合起来。

为什么不使用额外的均匀性?使用代表图像分辨率的vec2制服应该很容易解决此问题。如果这是唯一的解决方法,我想知道是否有其他方法可以在不使用任何额外制服的情况下解决此问题?我仍在努力争取着色器。穿制服是正常的,也可以说是聪明的事情。尤其是这个案子。不过,传入纹理分辨率可能是错误的解决方案。没有理由硬编码一些不需要硬编码的东西。但这对uv应用偏移有什么帮助?如果我理解正确,紫外线从-1变为1。我不能将像素偏移直接应用于uv,我必须计算纹理与gl_FragCoord相比的大小,但我不相信我没有统一的纹理大小,除非像上面的回答中所述使用webgl 2。如果我不支持IE,这将是完美的