Сначала ознакомьтесь с примером Qt quick\scenegraph\fboitem
. Он демонстрирует создание настраиваемого элемента управления QML с бэкэндом C ++ / OpenGL.
Также вы можете реализовать его с помощью ShaderEffect
элемента управления QML. Я рекомендую этот сайт https://www.shadertoy.com/new для отладки ваших шейдеров. Также вы можете использовать, например, Canvas
для передачи массивов вашему шейдеру в виде текстуры (ShaderEffect
не позволяет передавать массивы обычным образом, https://bugreports.qt.io/browse/QTBUG-50493).
Вот Возможная реализация вашего управления с динамикой c количество точек, цвета и позиции.
import QtQuick 2.12
import QtQuick.Controls 2.5
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: "Custom gradient"
Item {
anchors.fill: parent
layer.enabled: true
layer.effect: ShaderEffect {
readonly property var dataTex: dataCanvas
readonly property int count: dataCanvas.colors.length
fragmentShader: "
varying highp vec2 qt_TexCoord0;
uniform lowp float qt_Opacity;
uniform sampler2D dataTex;
const uniform lowp int count;
void main() {
vec3 col = 0.0;
for (int i = 0; i < count; i++) {
vec4 color = texture2D(dataTex, vec2(i / (float)count + 0.01, 0.0));
vec2 point = texture2D(dataTex, vec2(i / (float)count + 0.01, 1.0)).rg;
float dist = distance(qt_TexCoord0, point);
col += color * (1.0 - dist);
}
gl_FragColor = vec4(col, 1.0);
}
";
}
// Because ShaderEffect doesn't allow passing arrays to shader, we will
// convert arrays to graphical representation and pass them as texture.
Canvas {
id: dataCanvas
readonly property var colors: ["cyan", "red", "green", "darkblue", "yellow"]
readonly property var positions: [Qt.point(0,0),
Qt.point(10, parent.height - 20),
Qt.point(parent.width / 2, parent.height / 4),
Qt.point(parent.width, 0),
Qt.point(parent.width, parent.height)]
height: 2
width: colors.length
antialiasing: false
visible: false
onPaint: {
if (colors.length !== positions.length) {
console.error("Array size of 'colors' doesn't equal array size of 'positions'");
return;
}
var ctx = getContext("2d");
ctx.reset();
ctx.lineWidth = 1;
for (var i = 0; i < colors.length; i++) {
ctx.beginPath();
ctx.strokeStyle = colors[i];
ctx.moveTo(i, 0);
ctx.lineTo(i+1, 0);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = Qt.rgba(positions[i].x / parent.width, positions[i].y / parent.height, 0, 1);
ctx.moveTo(i, 1);
ctx.lineTo(i+1, 1);
ctx.stroke();
ctx.closePath();
}
}
}
}
}
Вот так это выглядит введите описание изображения здесь
Я не гуру OpenGL, поэтому этот код не идеален. Буду рад, если кто-нибудь отредактирует этот ответ, чтобы он стал лучше.