opengl 将纹理传递给程序:一次还是每次渲染?
opengl pass texture to program: once or at every rendering?
我有一个程序有两种纹理:一种来自视频,另一种来自图像。
对于图像纹理,我是否必须在每次渲染时将其传递给程序,还是只传递一次?我可以做吗
glActiveTexture(GLenum(GL_TEXTURE1))
glBindTexture(GLenum(GL_TEXTURE_2D), texture.id)
glUniform1i(textureLocation, 1)
就一次?我相信是这样,但在我的实验中,如果不涉及视频纹理,这就可以正常工作,但是一旦我添加了我在每个渲染过程中附加的视频纹理(因为它正在改变),获取图像的唯一方法是在每个渲染帧 运行 以上代码。
您应该在每次绘制前绑定纹理。您只需要设置一次位置。您也可以为此在着色器代码中执行 layout(binding = 1) 。位置制服与程序保持一致。纹理绑定是全局 GL 状态。还要注意 ActiveTexture:它是全局 GL 状态。
好的做法是:
- 创建程序时,一次,设置纹理位置(统一)
- 绘制时:SetActive(i)、Bind(i)、Draw、SetActive(i) Bind(0)、SetActive(0)
然后稍后针对冗余调用进行优化。
让我们剖析一下您在做什么,包括一些不必要的东西,以及 GL 做了什么。
首先,您在代码中进行的 none 的 C 风格转换是必要的。只需使用 GL_TEXTURE_2D
等代替 GLenum(GL_TEXTURE_2D)
。
glActiveTexture(GL_TEXTURE0 + i)
,其中 i
在 [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1]
范围内,选择当前活动的 纹理单元 。只要您不使用另一个有效的单元标识符调用 glActiveTexture
,改变纹理单元状态的命令将影响单元 i
。
一旦用当前活动的纹理单元i
调用glBindTexture(target, name)
,纹理单元的状态就会更改为引用name
指定的target
] 在着色器中使用适当的采样器对其进行采样时(即 name
可能绑定到 TEXTURE_2D
并且相应的样本必须是 sampler2D
)。您只能将一个纹理对象绑定到当前活动纹理单元的特定目标 - 因此,如果您需要在着色器中采样两个 2D 纹理,则需要使用两个纹理单元。
从上面,glUniform1i(samplerLocation, i)
的作用应该很明显了。
因此,如果您有两个 2D 纹理需要在着色器中采样,则需要两个纹理单元和两个采样器,每个都引用一个特定单元:
GLuint regularTextureName = 0;
GLunit videoTextureName = 0;
GLint regularTextureSamplerLocation = ...;
GLint videoTextureSamplerLocation = ...;
GLenum regularTextureUnit = 0;
GLenum videoTextureUnit = 1;
// setup texture objects and shaders ...
// make successfully linked shader program current and query
// locations, or better yet, assign locations explicitly in
// the shader (see below) ...
glActiveTexture(GL_TEXTURE0 + regularTextureUnit);
glBindTexture(GL_TEXTURE_2D, regularTextureName);
glUniform(regularTextureSamplerLocation, regularTextureUnit);
glActiveTexture(GL_TEXTURE0 + videoTextureUnit);
glBindTexture(GL_TEXTURE_2D, videoTextureName);
glUniform(videoTextureSampleLocation, videoTextureUnit);
你的片段着色器,我假设你将在其中进行采样,必须有相应的采样器:
layout(binding = 0) uniform sampler2D regularTextureSampler;
layout(binding = 1) uniform sampler2D videoTextureSampler;
就是这样。如果绑定到上述单元的两个纹理对象都正确设置,那么在每次片段着色器调用之前纹理内容是否动态变化并不重要——在许多场景中这是常见的地方,例如延迟渲染或任何其他渲染到纹理算法,因此您并没有完全用某些视频纹理开辟新天地。
关于你需要多久做一次这个问题:你需要在需要做的时候做——不要改变不需要改变的状态。如果您从不更改相应纹理单元的绑定,则根本不需要重新绑定纹理。正确设置它们一次,不要管它们。
采样器绑定也是如此:如果您不使用着色器对其他纹理对象进行采样,则根本不需要更改着色器程序状态。设置一次,不用管它。
简而言之:如无必要,请不要更改状态。
编辑:我不太确定是否是这种情况,但是如果您使用同一个着色器和一个采样器 both 纹理在单独的着色器调用中,你必须改变一些东西,但你猜怎么着,这就像让采样器引用另一个纹理单元一样简单:
// same texture unit setup as before
// shader program is current
while (rendering)
{
glUniform(samplerLocation, regularTextureUnit);
// draw call sampling the regular texture
glUniform(samplerLocation, videoTextureUnit);
// draw call sampling teh video texture
}
我有一个程序有两种纹理:一种来自视频,另一种来自图像。
对于图像纹理,我是否必须在每次渲染时将其传递给程序,还是只传递一次?我可以做吗
glActiveTexture(GLenum(GL_TEXTURE1))
glBindTexture(GLenum(GL_TEXTURE_2D), texture.id)
glUniform1i(textureLocation, 1)
就一次?我相信是这样,但在我的实验中,如果不涉及视频纹理,这就可以正常工作,但是一旦我添加了我在每个渲染过程中附加的视频纹理(因为它正在改变),获取图像的唯一方法是在每个渲染帧 运行 以上代码。
您应该在每次绘制前绑定纹理。您只需要设置一次位置。您也可以为此在着色器代码中执行 layout(binding = 1) 。位置制服与程序保持一致。纹理绑定是全局 GL 状态。还要注意 ActiveTexture:它是全局 GL 状态。
好的做法是:
- 创建程序时,一次,设置纹理位置(统一)
- 绘制时:SetActive(i)、Bind(i)、Draw、SetActive(i) Bind(0)、SetActive(0)
然后稍后针对冗余调用进行优化。
让我们剖析一下您在做什么,包括一些不必要的东西,以及 GL 做了什么。
首先,您在代码中进行的 none 的 C 风格转换是必要的。只需使用 GL_TEXTURE_2D
等代替 GLenum(GL_TEXTURE_2D)
。
glActiveTexture(GL_TEXTURE0 + i)
,其中 i
在 [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1]
范围内,选择当前活动的 纹理单元 。只要您不使用另一个有效的单元标识符调用 glActiveTexture
,改变纹理单元状态的命令将影响单元 i
。
一旦用当前活动的纹理单元i
调用glBindTexture(target, name)
,纹理单元的状态就会更改为引用name
指定的target
] 在着色器中使用适当的采样器对其进行采样时(即 name
可能绑定到 TEXTURE_2D
并且相应的样本必须是 sampler2D
)。您只能将一个纹理对象绑定到当前活动纹理单元的特定目标 - 因此,如果您需要在着色器中采样两个 2D 纹理,则需要使用两个纹理单元。
从上面,glUniform1i(samplerLocation, i)
的作用应该很明显了。
因此,如果您有两个 2D 纹理需要在着色器中采样,则需要两个纹理单元和两个采样器,每个都引用一个特定单元:
GLuint regularTextureName = 0;
GLunit videoTextureName = 0;
GLint regularTextureSamplerLocation = ...;
GLint videoTextureSamplerLocation = ...;
GLenum regularTextureUnit = 0;
GLenum videoTextureUnit = 1;
// setup texture objects and shaders ...
// make successfully linked shader program current and query
// locations, or better yet, assign locations explicitly in
// the shader (see below) ...
glActiveTexture(GL_TEXTURE0 + regularTextureUnit);
glBindTexture(GL_TEXTURE_2D, regularTextureName);
glUniform(regularTextureSamplerLocation, regularTextureUnit);
glActiveTexture(GL_TEXTURE0 + videoTextureUnit);
glBindTexture(GL_TEXTURE_2D, videoTextureName);
glUniform(videoTextureSampleLocation, videoTextureUnit);
你的片段着色器,我假设你将在其中进行采样,必须有相应的采样器:
layout(binding = 0) uniform sampler2D regularTextureSampler;
layout(binding = 1) uniform sampler2D videoTextureSampler;
就是这样。如果绑定到上述单元的两个纹理对象都正确设置,那么在每次片段着色器调用之前纹理内容是否动态变化并不重要——在许多场景中这是常见的地方,例如延迟渲染或任何其他渲染到纹理算法,因此您并没有完全用某些视频纹理开辟新天地。
关于你需要多久做一次这个问题:你需要在需要做的时候做——不要改变不需要改变的状态。如果您从不更改相应纹理单元的绑定,则根本不需要重新绑定纹理。正确设置它们一次,不要管它们。
采样器绑定也是如此:如果您不使用着色器对其他纹理对象进行采样,则根本不需要更改着色器程序状态。设置一次,不用管它。
简而言之:如无必要,请不要更改状态。
编辑:我不太确定是否是这种情况,但是如果您使用同一个着色器和一个采样器 both 纹理在单独的着色器调用中,你必须改变一些东西,但你猜怎么着,这就像让采样器引用另一个纹理单元一样简单:
// same texture unit setup as before
// shader program is current
while (rendering)
{
glUniform(samplerLocation, regularTextureUnit);
// draw call sampling the regular texture
glUniform(samplerLocation, videoTextureUnit);
// draw call sampling teh video texture
}