I have a QML Scene3D with 2 viewports, left and right half of window. The scene contains two cameras (one per viewport) and a torus mesh. I want to use a viewport-specific material for the same torus, i.e. different QMaterials (QEffects, QShaderPrograms, ...) when rendering in the left and right viewport respectively.
// main.qml
Entity {
id: rootEntity
components: [
MyFrameGraph {
camLeft: cameraLeft
camRight: cameraRight
},
InputSettings { }
]
Camera {
id: cameraLeft
projectionType: CameraLens.PerspectiveProjection
position: Qt.vector3d( 0.0, 0.0, -200.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
Camera {
id: cameraRight
projectionType: CameraLens.PerspectiveProjection
position: Qt.vector3d( 0.0, 200.0, 0.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
TorusMesh {
id: torusMesh
radius: 20
minorRadius: 5
}
Transform {
id:torusTransform
}
Material{
id: myTorusMaterial
effect: MyEffect{}
}
Entity {
id: torus
components: [torusMesh,torusTransform,myTorusMaterial]
}
}
My FrameGraph contains two branches for the two viewports, whereas the leaf nodes are RenderPassFilters.
//MyFrameGraph.qml
RenderSettings {
id: root
property Camera camLeft
property Camera camRight
activeFrameGraph: RenderSurfaceSelector {
id: surfaceSelector
Viewport {
id: mainViewport
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
ClearBuffers {
buffers: ClearBuffers.ColorDepthBuffer
clearColor: "black"
}
Viewport {
normalizedRect: Qt.rect(0.0, 0.0, 0.5, 1)
CameraSelector {
camera: root.camLeft
RenderStateSet {
renderStates: [
DepthTest {depthFunction: DepthTest.Less}
]
RenderPassFilter {
matchAny: [FilterKey { name: "pass"; value: "myMaterialLeft" }]
}
}
}
}
Viewport {
normalizedRect: Qt.rect(0.5, 0.0, 0.5, 1)
CameraSelector {
camera: root.camRight
RenderStateSet {
renderStates: [
DepthTest {depthFunction: DepthTest.Less}
]
RenderPassFilter {
matchAny: [FilterKey { name: "pass"; value: "myMaterialRight" }]
}
}
}
}
}
}
}
In my custom Material/Effects I use FilterKeys in the RenderPass object.
//MyEffect.qml
Effect {
id: root
property color maincolor: Qt.rgba(0.0, 1.0, 0.0, 1.0)
ShaderProgram {
id: myShaderLeft
vertexShaderCode: loadSource("qrc:/shader/myShaderLeft.vert")
fragmentShaderCode: loadSource("qrc:/shader/myShaderLeft.frag")
}
ShaderProgram {
id: myShaderRight
vertexShaderCode: loadSource("qrc:/shader/myShaderRight.vert")
fragmentShaderCode: loadSource("qrc:/shader/myShaderRight.frag")
}
parameters: [
Parameter {
name: "maincolor"
value: Qt.vector3d(root.maincolor.r, root.maincolor.g, root.maincolor.b)
}
]
techniques: [
Technique {
filterKeys: [FilterKey { name: "renderingStyle"; value: "forward" }]
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 3
minorVersion: 1
}
RenderPass {
id:renderPassLeft
filterKeys: [ FilterKey { name: "pass"; value: "myMaterialLeft" } ]
shaderProgram: myShaderLeft
renderStates: [CullFace { mode: CullFace.NoCulling }]
}
RenderPass {
id: renderPassRight
filterKeys: [ FilterKey { name: "pass"; value: "myMaterialRight" } ]
shaderProgram: myShaderRight
renderStates: [CullFace { mode: CullFace.NoCulling }]
}
renderPasses:[renderPassLeft,renderPassRight]
}
]
}
This works as expected, the object is rendered with myShaderLeft
in the left viewport and with myShaderRight
in the right viewport.
Now I want to use an default Qt-material (QMetalRoughMaterial) when rendering in the left viewport, and my custom material/effect when rendering in the right viewport. How can I achieve that?
An idea was to access the ShaderProgram of the MetalRoughMaterial through metalRougMaterial.effect.techniques[0].renderPasses[0].shaderProgram
and use it one of the RenderPasses of my custom Material/Effect. However, metalRougMaterial.effect.techniques
returns an undefined object.
MetalRoughMaterial {
id: metalRoughMaterial
baseColor: "red"
}