本文介绍了是否可以在着色器中访问预设的纹理单元?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL;DR: 我已经激活纹理并将纹理绑定到纹理单元 1-4,现在我希望在着色器中使用它们而不使用程序特定的统一位置.是否可以使用全局"从纹理读取数据?纹理单元?

我很难理解如何在 webgl 中访问纹理.在

上面你可以看到着色器程序(金色)有两个统一的decaldiffuse.

  • decal 设置为 3,因此它引用纹理单元 3.纹理单元 3 绑定到 decalTexture(F 的图像)

  • diffuse 设置为 6,因此它引用纹理单元 6.纹理单元 3 绑定到 diffuseTexture(一个 4x4 棋盘)

请注意,纹理单元 0 也绑定到 decalTexture 但着色器程序并未引用纹理单元 0,因此至少出于绘制像素的目的,换句话说,执行着色器程序,纹理未使用单元 0.

TL;DR: I've activated and bound textures to textureunits 1-4 and now I wish to use them within shaders without using a program specific uniform position. Is it possible to read data from textures using the "global" texture units?

I'm having a bit of a hard time understanding how to access textures in webgl. Here in this tutorial on textures it says "Texture units are a global array of references to textures.", and this sounds great. I've bound my textures using

gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);

where i is the index of the newly created texture and tex is the texture itself.

But it doesn't give an example of how to access the texture within a shader using this global reference. In this tutorial from the same page it does give an example of how to access the textures from within a shader, but only when using an uniform position (much like how an attribute is accessed), which requires a program (and thus, removing the global aspect, in a way, since it's dependent on the program to be accessed). In this preceding tutorial any details of how to actually set up the texture "u_texture" is skipped altogether.

In short, I have two programs, and I wish to use textures globally in both of them without having to getUniformLocation on each program, if it's possible to do so. Seeing the promises of texture units, I thought I could use them, but I don't know how to actually do something like

sampler2D textureUnit2;

within the shaders. Is this possible? Am i confusing the implementation of the textureUnits with the practicality of using them?

Many thanks!

解决方案

It is not possible to do so.

The texture units are global. You can think of it just like a global array in JavaScript

const textureUnits = [
  { TEXTURE_2D: someTexture, },       // unit 0
  { TEXTURE_2D: someOtherTexture, },  // unit 1
  { TEXTURE_2D: yetAnotherTexture, }, // unit 2
  ...
];

You can bind a texture to a texture unit by first calling gl.activeTexture and then calling gl.bindTexture. Example:

const unit = 2;
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, yetAnotherTexture);

yetAnotherTexture is now bound to texture unit 2

Separately you have shader programs. To access a texture you declare a uniform sampler2d someName; in your shader.

uniform sampler2D foobar;

Think of that as an index into the texture units. You then need to set the index (tell the shader program which global texture unit to use)

const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);

The texture units themselves are global. The uniforms of a program are unique to each program. You need to set them to tell them which texture unit you want that uniform to reference. Uniforms default to 0 so if you want them to reference texture unit 0 then you don't need to set them but for any other texture unit you do need to set them.

Imagine GLSL's texture2D function was written in JavaScript. It would work something like

function texture2d(sampler, texcoord) {
  const texture = textureUnits[sampler].TEXTURE_2D;
  return getColorFromTextureAtTexcoord(texture, texcoord);
}

So if I did this

uniform sampler2D foobar;
varying vec2 v_texcoord;

void main() {
  gl_FragColor = texture2D(foobar, v_texcoord);
}

Then I set the foobar uniform to 2

const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);

It's going to reference the global texture unit at index 2.

Note: This code in your question

gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);

seems wrong. It should use TEXTURE0 as a base, not TEXTURE1

gl.activeTexture(gl.TEXTURE0 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);

This diagram might help visualize how it works

Above you can see shader program (gold) has two uniforms decal and diffuse.

  • decal is set to 3 so it's referencing texture unit 3. texture unit 3 is bound to the decalTexture (an image of a F)

  • diffuse is set to 6 so it's referencing texture unit 6. texture unit 3 is bound to the diffuseTexture (a 4x4 checkerboard)

Note that texture unit 0 is also bound to the decalTexture but the shader program is not referencing texture unit 0 so at least for the purpose of drawing pixels, in other words executing the shader program, texture unit 0 is not being used.

这篇关于是否可以在着色器中访问预设的纹理单元?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 00:20