如何在WGSL着色器中重复纹理?

时间:2019-12-25 16:01:27

标签: glsl webgl textures

我正在着色器程序中使用非2的幂次纹理。我正在尝试实现重复的滚动文本。滚动效果很好,但是当我尝试通过顶点着色器中的逻辑使纹理重复时,我突然得到一个四边形,其整个范围内都有一组拉伸像素。我认为这是由于过滤算法导致的。

作为背景,我想在顶点程序中生成纹理坐标,因为我随后在片段程序中对其进行了进一步的变形,并且如果片段程序的输入已经正确以解决滚动问题,则更易于管理。请注意,我在相应的片段着色器中访问textureCoordinateVarying

此方法有效,尽管在文本滚动时没有重复的纹理:

attribute vec4 position;
attribute vec2 texcoord;

uniform mat3 matrixUniform;
uniform float horizontalTextureOffsetUniform;

varying vec2 textureCoordinateVarying;

void main() {
   gl_Position = vec4((matrixUniform * vec3(position.x, position.y, 1)).xy, 0, 1);
   textureCoordinateVarying = vec2(
//I get a nice scrolling animation by changing the offset here, but the texture doesn't repeat, since it is NPO2 and therefore doesn't have repeating enabled
        texcoord.x + horizontalTextureOffsetUniform,
        texcoord.y
    );
}

Correct Scroll w/ No Repeate

另一方面,正如您所看到的,这给了我一张延伸的图像:

attribute vec4 position;
attribute vec2 texcoord;

uniform mat3 matrixUniform;
uniform float horizontalTextureOffsetUniform;

varying vec2 textureCoordinateVarying;

void main() {
   gl_Position = vec4((matrixUniform * vec3(position.x, position.y, 1)).xy, 0, 1);
   textureCoordinateVarying = vec2(
\\Note how I am using fract here, which should make the texture repeat at the 1.0 texture boundary, but instead renders a blurry stretched texture
        fract(texcoord.x + horizontalTextureOffsetUniform),
        texcoord.y
    );

}

Stretched image during scroll

关于如何解决这个问题的任何想法?

谢谢!

1 个答案:

答案 0 :(得分:0)

您需要在片段着色器(而不是顶点着色器)中执行重复数学运算。

const gl = document.querySelector('canvas').getContext('webgl');

const vs = `
void main() {
  gl_Position = vec4(0,0,0,1);
  gl_PointSize = 100.0;
}`;

const fs = `
precision highp float;
uniform sampler2D tex;
uniform vec2 offset;
void main() {
  gl_FragColor = texture2D(tex, fract(gl_PointCoord.xy + offset));
}`;

// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

// calls gl.createTexture, gl.texImage2D, gl.texParameteri
const tex = twgl.createTexture(gl, {
  src: 'https://i.imgur.com/v38pV.jpg'
});


function render(time) {
  time *= 0.001;
  
  gl.useProgram(programInfo.program);
  
  // calls gl.activeTexture, gl.bindTexture, gl.uniform
  twgl.setUniformsAndBindTextures(programInfo, {
    tex,
    offset: [time, time * 0.1],
  });

  gl.drawArrays(gl.POINTS, 0, 1);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>