【问题标题】:How can I repeat a texture within a WGSL shader?如何在 WGSL 着色器中重复纹理?
【发布时间】:2020-04-16 04:42:48
【问题描述】:

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

作为背景,我想在顶点程序中生成纹理坐标,因为我会在片段程序中对它们进行进一步的扭曲,如果片段程序的输入已经正确考虑滚动,则更容易管理.请注意,我在相应的片段着色器中访问了 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
    );
}

另一方面,这给了我一个拉伸的图像,如你所见:

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
    );

}

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

谢谢!

【问题讨论】:

  • 重复纹理坐标不能使用简单的fract()。想象一个顶点的纹理 x 坐标为 0.0,另一个为 1.0。然后,当您使用 0.1 的偏移量时,两个顶点都会得到 0.1,因为 fract(0.0 + 0.1) = 0.1 和 fract(1.0 + 0.1) = 0.1
  • 实际上,似乎问题出在我使用 fract (或 mod(x, 1.0) )上。如果我只是将 texcoord.x 作为 fract(texcoord.x) 传递,则不会渲染任何内容。我认为纹理坐标是从 0-1.0?我错过了什么?编辑:我在 httpdigest 响应时发布了这个权利
  • 嗨 httpdigest,你描述的是我想要的......我假设 1.0 坐标是纹理的边缘,所以如果我想让它在四边形中重复,它应该处理方式与 0.0 相同。我觉得我在这里遗漏了一些非常基本的东西。
  • 不,这不是你想要的。如果将 0.1 分配给两个顶点,则纹理坐标不会在多个纹素之间进行插值,而只会对单个纹素进行采样,这就是您所看到的。纹理重复只能在片段着色器(未修改,大于一个纹理坐标)或通过纹理过滤(GL_REPEAT)中完成。
  • 有意思,谢谢你的解释。鉴于我不能在非二次幂纹理上使用 GL_REPEAT,您认为这在片段着色器中可行吗?一旦有时间,我将尝试将逻辑移到那里。现在,圣诞电话。

标签: glsl webgl textures


【解决方案1】:

您需要在片段着色器中进行重复计算,而不是在顶点着色器中。

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>

【讨论】:

  • 谢谢,我可以确认这是正确的建议。
猜你喜欢
  • 2013-02-20
  • 1970-01-01
  • 2021-11-19
  • 1970-01-01
  • 2013-09-17
  • 1970-01-01
  • 2012-12-27
  • 1970-01-01
  • 2011-12-29
相关资源
最近更新 更多