C

Qt Quick Ultralite perspective_transforms Example

/****************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/
import QtQuick 2.12 import Constants 1.0 Rectangle { id: cover property string texture property int coverIndex property CoverFlowState state property matrix4x4 coverTransform: calcCoverTransform() z: calcFinalZ() Image { id: coverImageBase source: cover.texture transform: Matrix4x4 { matrix: coverTransform } opacity: 1.0 } Image { id: mirrorImageBase visible: cover.state.showReflection source: cover.texture transform: Matrix4x4 { matrix: calcReflectionTransform() } opacity: 0.1 } // Elementary matrix generations functions function mtxIdentity() : matrix4x4 { return Qt.matrix4x4(1, 0, 0, 0, 0, 1 ,0, 0, 0, 0 ,1, 0, 0, 0, 0, 1) } function mtxTranslate(x : real, y : real, z : real) : matrix4x4 { return Qt.matrix4x4(1, 0, 0, x, 0, 1 ,0, y, 0, 0 ,1, z, 0, 0, 0, 1) } function mtxScale(x : real, y : real, z : real) : matrix4x4 { return Qt.matrix4x4(x, 0, 0, 0, 0, y ,0, 0, 0, 0 ,z, 0, 0, 0, 0, 1) } function mtxRotX(angle : real) : matrix4x4 { var radians = Math.PI * angle / 180 var sinAngle = Math.sin(radians) var cosAngle = Math.cos(radians) return Qt.matrix4x4(1, 0, 0, 0, 0, cosAngle, -sinAngle, 0, 0, sinAngle, cosAngle, 0, 0, 0, 0, 1) } function mtxRotY(angle : real) : matrix4x4 { var radians = Math.PI * angle / 180 var sinAngle = Math.sin(radians) var cosAngle = Math.cos(radians) return Qt.matrix4x4( cosAngle, 0, sinAngle, 0, 0, 1, 0, 0, -sinAngle, 0, cosAngle, 0, 0, 0, 0, 1) } function mtxPerspective(fov : real, aspectRatio : real, near : real, far : real) : matrix4x4 { var fovRadians = (fov * Math.PI / 180) / 2 var fovCotan = Math.cos(fovRadians) / Math.sin(fovRadians) var s = 1.0 / (near - far) return Qt.matrix4x4(fovCotan / aspectRatio, 0, 0, 0, 0, fovCotan, 0, 0, 0, 0, (near + far) * s, (2 * near * far) * s, 0, 0, -1, 1) } // Calc camera transform matrix function calcPostMatrix(x : real, y : real, w : real, h : real, fov : real, viewDist : real) : matrix4x4 { var t1 = mtxTranslate(x, y, 0) var s2 = mtxScale(w / 2, h / 2, 1) var t3 = mtxTranslate(1, 1, 0) var p4 = mtxPerspective(fov, w / h, 0.1, 100) var t5 = mtxTranslate(0, 0, -viewDist) return t1.times(s2.times(t3.times(p4.times(t5)))) } // Calc initial cover transform function calcPreMatrix(coverSize : real) : matrix4x4 { var t1 = mtxTranslate(-1, -1, 0) var s2 = mtxScale(2 / coverSize, 2 / coverSize, 1) return t1.times(s2) } // Calculate transforms for individual transform types function calcPosMatrixCarousel() : matrix4x4 { var angle = (coverIndex - state.selectedCover) / state.numberOfCovers * 360; var r1 = mtxRotX(state.viewAngle) var t2 = mtxTranslate(0, state.cameraHeight, 0) var r3 = mtxRotY(angle) var t4 = mtxTranslate(0, 0, state.carouselZ) var r5 = mtxRotX(-state.viewAngle/4) var s6 = mtxScale(state.coverScaling, state.coverScaling, 1) return r1.times(t2.times(r3.times(t4.times(r5.times(s6))))) } function calcPosMatrixCircle() : matrix4x4 { var angle = (coverIndex - state.selectedCover) / state.numberOfCovers * 360; var radians = Math.PI * angle / 180 var sinAngle = Math.sin(radians) var cosAngle = Math.cos(radians) var r1 = mtxRotX(state.viewAngle) var t2 = mtxTranslate(0, state.cameraHeight, 0) var t3 = mtxTranslate(state.circleRadius * sinAngle, 0, state.circleRadius * cosAngle) var s4 = mtxScale(state.coverScaling, state.coverScaling, 1) return r1.times(t2.times(t3.times(s4))) } function calcPosMatrixCircle2D() : matrix4x4 { var angle = (coverIndex - state.selectedCover) / state.numberOfCovers * 360; var radians = Math.PI * angle / 180 var sinAngle = Math.sin(radians) var cosAngle = Math.cos(radians) var r1 = mtxRotX(state.viewAngle) var t2 = mtxTranslate(0, state.cameraHeight, 0) var t3 = mtxTranslate(state.circleRadius * sinAngle, 0, state.circleRadius * cosAngle) var r4 = mtxRotX(-state.viewAngle) var s5 = mtxScale(state.coverScaling, state.coverScaling, 1) return r1.times(t2.times(t3.times(r4.times(s5)))) } function calcPosMatrixPerspective() : matrix4x4 { var fract = Math.min(Math.abs(coverIndex - state.selectedCover), 1) var dir = coverIndex <= state.selectedCover ? 1 : -1 var ta1 = mtxTranslate(0, 0, (1 - fract) * state.perspectiveViewCenterZ) var ta2 = mtxTranslate(fract * ((coverIndex - state.selectedCover) * state.perspectiveViewCoverDist - dir * state.perspectiveViewCenterDist), 0, 0) var ra3 = mtxRotY(dir * fract * state.perspectiveViewMaxRot) return ta1.times(ta2.times(ra3)) } // Calculates transform matrix for a given cover flow type function calcMatrixForType(type : int) : matrix4x4 { switch (type) { case CoverFlowType.Carousel: return calcPosMatrixCarousel() case CoverFlowType.Circle: return calcPosMatrixCircle() case CoverFlowType.Circle2D: return calcPosMatrixCircle2D() case CoverFlowType.Perspective: return calcPosMatrixPerspective() } return mtxIdentity() } // Calculate final cover transformation considering morphRatio function calcCoverTransform() : matrix4x4 { var postMatrix = calcPostMatrix(state.coverFlowX, state.coverFlowY, state.coverFlowW, state.coverFlowH, state.fov, state.viewDistance) var preMatrix = calcPreMatrix(state.coverSize) var currentShape = postMatrix.times(calcMatrixForType(state.currentViewType).times(preMatrix)) var oldShape = postMatrix.times(calcMatrixForType(state.previousViewType).times(preMatrix)) return currentShape.times(state.morphRatio).plus(oldShape.times(1 - state.morphRatio)) } // Calculate reflection transform, using cover transform as a base function calcReflectionTransform() : matrix4x4 { var scaleMirror = Qt.matrix4x4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) var translateMirror = Qt.matrix4x4(1, 0, 0, 0, 0, 1, 0, state.reflectionDistance, 0, 0, 1, 0, 0, 0, 0, 1) return cover.coverTransform.times(translateMirror.times(scaleMirror)) } // Calculate cover depth along z-axis function calcFinalZ() : real { var coverTransform = cover.coverTransform var x = state.coverSize/2 var y = state.coverSize/2 var d = coverTransform.m41 * x + coverTransform.m42 * y + coverTransform.m44 var fX = (coverTransform.m11 * x + coverTransform.m12 * y + coverTransform.m14) / d var fZ = (coverTransform.m31 * x + coverTransform.m32 * y + coverTransform.m34) / d var littleX = Math.abs(fX - state.coverFlowX - state.coverFlowW / 2) return -fZ * 100000 - littleX } }