绑定纹理时,它将绑定到当前活动的纹理图像单元(请参见
Binding textures to samplers
).
活动纹理单元可以通过以下方式选择:
glActiveTexture
. 默认纹理单位为
GL_TEXTURE0
.
必须提供给纹理采样器统一的值不是纹理的名称,而是纹理单位(编号),纹理绑定到:
int texture_unit = 0; // <----- e.g. texture unit 0
glActiveTexture( GL_TEXTURE0 + texture_unit );
glBindTexture( GL_TEXTURE_2D, m_texture );
.....
m_program->bind();
m_program->setUniformValue( "source", texture_unit ); // <----- texture unit
对于
QOpenGLTexture
对象可以通过以下方式选择纹理单元
QOpenGLTexture::bind
:
int texture_unit = 1; // <----- e.g. texture unit 1
QOpenGLTexture texture(image);
texture.bind( texture_unit );
m_program->bind();
m_program->setUniformValue( "source", texture_unit ); // <----- texture unit
注意,由于OpenGL 4.2,纹理单元可以在着色器中通过
Binding point
:
layout(binding = 0) uniform sampler2D source; // binding = 0 -> texture unit 0
答案的扩展:
以下代码将通过着色器处理将a图像绘制到整个小部件。最后,渲染图像从GPU读回:
class GLWidget : public QOpenGLWidget
{
.....
QOpenGLShaderProgram * m_program = nullptr;
QOpenGLTexture * m_texture = nullptr;
};
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
QImage img("E:\\pictures\\0151.jpg");
m_texture = new QOpenGLTexture( img );
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader);
m_program->bindAttributeLocation("vPosition", 0);
m_program->link();
}
void GLWidget::paintEvent(QPaintEvent *event)
{
// celar the framebuffer
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// bind the texture
uint texture_unit = 1;
m_texture->bind( texture_unit );
// activate the shader
m_program->bind();
m_program->setUniformValue( "source", texture_unit );
m_program->setUniformValue( "grid", grid );
m_program->setUniformValue( "dividerValue", dividerValue );
m_program->setUniformValue( "step_x", step_x );
m_program->setUniformValue( "step_y", step_y );
// draw a quad over the entire widget
GLfloat vertices[]{ -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };
m_program->enableAttributeArray(0);
m_program->setAttributeArray(0, GL_FLOAT, vertices, 2);
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
m_program->disableAttributeArray(0);
// release the shader
m_program->release();
// read the rendered image
int width = ....;
int height = ....;
unsigned char *pixels = new unsigned char[width * height * 4];
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
QImage *img = new QImage( pixels, width, height, QImage::Format_RGBA8888 );
.....
}
此外,还必须对顶点着色器和片段着色器进行一些更改。在顶点着色器中,必须将顶点位置传递给片段着色器:
attribute vec2 vPosition;
varying vec2 v_pos;
void main()
{
v_pos = vPosition.xy;
gl_Position = vec4(vPosition.xy, 0.0, 1.0);
}
在片段着色器中,必须从顶点位置计算纹理坐标:
varying vec2 v_pos;
void main()
{
vec2 uv = v_pos.xy * 0.5 + 0.5;
....
}
另请参见
glwidget.cpp Example File
.