Я разрабатываю простую реализацию QQuickItem в C ++ на основе примера «openglunderqml», поставляемого с Qt. Я сделал несколько модификаций, чтобы использовать разные шейдеры и две загружаемые текстуры. Идея состоит в том, что шейдеры будут плавно переходить между двумя текстурами (которые по сути являются просто изображениями, которые я загрузил в текстуры).
Когда я помещаю этот QQuickItem в файл QML и запускаю его, все работает нормально. Изображения пересекаются между собой (я настроил анимацию свойств, чтобы они не затухали), и все выглядит нормально. Однако, если я добавлю другие элементы, такие как текст, текст не будет отображаться должным образом — только маленькие блоки странной формы. Если я добавлю изображение, все будет очень странно. Вместо того, чтобы QQuickItem отображал блок, в котором он должен отображаться, он отображает весь экран и вверх ногами. Насколько я могу судить, другое изображение никогда не загружается.
Я думаю, что я, должно быть, делаю не то, что должен, но я понятия не имею, что. Обратите внимание, что первый блок кода содержит шейдеры и средства рендеринга, второй содержит функцию loadNewTexture (), которая загружает новое изображение в текстуру (вызывается только один раз для текстуры — не каждый рендеринг), а третий содержит файл QtQuick .qml. ,
Вот код opengl (в методе QQuckItem :: Paint):
// Builds the OpenGL shaders that handle the crossfade
if (!m_program) {
m_program = new QOpenGLShaderProgram();
// Shader loads coordinate positions
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute vec2 position;""varying vec2 texcoord;""void main() {"" gl_Position = vec4(position, 0.0, 1.0);"" texcoord = position * vec2(0.5) + vec2(0.5);""}");
// Shader does the crossfade
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
"uniform lowp float xfade;""uniform sampler2D textures[2];""varying vec2 texcoord;""void main() {"" gl_FragColor = mix("" texture2D(textures[0], texcoord),"" texture2D(textures[1], texcoord),"" xfade"" );""}");
m_program->bindAttributeLocation("vertices", 0);
m_program->link();
connect(window()->openglContext(), SIGNAL(aboutToBeDestroyed()),
this, SLOT(cleanup()), Qt::DirectConnection);
}
m_program->bind();
// Loads corner vertices as triangle strip
m_program->enableAttributeArray(0);
float values[] = {
-1, -1,
1, -1,
-1, 1,
1, 1
};
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
// Loads the fade value
m_program->setUniformValue("xfade", (float) m_thread_xfade);
glEnable(GL_TEXTURE_2D);
// Check if a new texture needs to be loaded
if (!new_source_loaded && !m_adSource.isEmpty())
new_source_loaded = loadNewTexture(m_adSource);
// Loads texture 0 into the shader
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
m_program->setUniformValue("textures[0]", 0);
// Loads texture 1 into the shader
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
m_program->setUniformValue("textures[1]", 1);
// Sets the OpenGL render area to the space given to this components
glViewport((GLint) this->x(), (GLint) this->y(), (GLint) this->width(), (GLint) this->height());
// Sets some parameters
glDisable(GL_DEPTH_TEST);
// Sets the clear color (backround color) to black
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
// Draws triangle strip
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
// Cleans up vertices
m_program->disableAttributeArray(0);
m_program->release();
Функция loadNewTexture ():
bool AdRotator::loadNewTexture(QUrl source) {
// Load the image from source url
QImage image(source.path());
// Check that the image was loaded properly
if (image.isNull()) {
qDebug() << QString("AdRotator::loadTexture: Loading image from source: ") << source.toString() << QString(" failed.");
return false;
}
// Update this as the active texture
active_texture = !active_texture;
// Convert into GL-friendly format
QImage GL_formatted_image = QGLWidget::convertToGLFormat(image);
// Check that the image was converted properly
if (image.isNull()) {
qDebug() << QString("AdRotator::loadTexture: Converting image from source: ") << source.toString() << QString(" failed.");
return false;
}
// Generate the texture base
glGenTextures(1, &textures[active_texture]);
glBindTexture(GL_TEXTURE_2D, textures[active_texture]);
// Give texture parameters (scaling and edging options)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Load pixels from image into texture
glTexImage2D(
GL_TEXTURE_2D, 0, /* target, level of detail */
GL_RGBA, /* internal format */
GL_formatted_image.width(), GL_formatted_image.height(), 0, /* width, height, border */
GL_RGBA, GL_UNSIGNED_BYTE, /* external format, type */
GL_formatted_image.bits() /* pixels */
);
if (textures[active_texture] == 0) qDebug() << QString("New Texture post-load failed.");
return true;
}
Файл .qml:
import QtQuick 2.0
Item {
width: 1920
height: 1080
/* Image{} element breaks things
Image {
id: image1
x: 0
y: 0
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 0
sourceSize.height: 1080
sourceSize.width: 1920
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: "images/background.png"}*/
/* The QQuickItem */
ImageCrossfader {
x: 753
y: 107
width: 1150
height: 865
}
}
Недавно я выполнил почти то же самое упражнение и (не выполняя ваш код и работая только с одной текстурой), я думаю, у меня может быть представление о том, что вы пропустили: вы должны убедиться, что Конечный автомат OpenGL остается в конце вашей функции рисования (более или менее) точно как вы нашли это в начале. Вы выпустили программу шейдера и отключили атрибут массива, но не связали две текстуры в ваших двух текстурных единицах. Следующее в конце вашей функции-члена рисования должно помочь:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
Кроме этого, два дальнейших комментария:
Обратите внимание, что ваш image1 Изображение из файла QML полностью скрывает ваш элемент ImageCrossfader (если я не ошибаюсь, интерпретируя свойство якоря). Все, что вы добавите в свою QML-сцену, будет нарисовано над ваш подкладка opengl (отсюда и название;)).
Вы можете безопасно удалить все glEnable (), glDisable () а также glBlendFunc () звонки. На самом деле их удаление должно сделать ваш код более безопасным, потому что чем меньше вы изменяете, тем меньше изменений вы должны помнить, чтобы вернуться.
Других решений пока нет …