Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 58 additions & 52 deletions meshroom/ui/qml/Controls/DirectionalLightPane.qml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects // for OpacityMask & Glow
import QtQuick.Shapes
import MaterialIcons 2.2
import Utils 1.0

Expand All @@ -13,7 +13,6 @@ import Utils 1.0
* @param lightYawValue - directional light yaw (degrees)
* @param lightPitchValue - directional light pitch (degrees)
*/

FloatingPane {
id: root

Expand All @@ -36,9 +35,9 @@ FloatingPane {
// update 2d controller if pitch value changed
onLightPitchValueChanged: { lightBallController.update() }

// pane properties
anchors.margins: 0
padding: 5
radius: 0

ColumnLayout {
anchors.fill: parent
Expand Down Expand Up @@ -152,65 +151,72 @@ FloatingPane {
y = controllerRadius * Math.sin(angleRad)
}

// compute distance function for light gradient emulation
var distanceRatio = Math.min(distance, controllerRadius) / controllerRadius
var distanceFunct = distanceRatio * distanceRatio * 0.3

// update light point
lightPoint.x = lightPoint.startOffset + x
lightPoint.y = lightPoint.startOffset + y

// update light gradient
lightGradient.angle = angleRad * (180 / Math.PI) // radians to degrees
lightGradient.horizontalRadius = controllerSize * (1 - distanceFunct)
lightGradient.verticalRadius = controllerSize * (1 + distanceFunct)
lightGradient.horizontalOffset = x * (1 - distanceFunct)
lightGradient.verticalOffset = y * (1 - distanceFunct)
}

RadialGradient {
id: lightGradient

// light ball controller shapes
Shape {
anchors.centerIn: parent
width: controllerSize
height: width
horizontalRadius: controllerSize
verticalRadius: controllerSize
angle: 0
gradient: Gradient {
GradientStop { position: 0.00; color: "#FFFFFFFF" }
GradientStop { position: 0.10; color: "#FFAAAAAA" }
GradientStop { position: 0.50; color: "#FF0C0C0C" }
}
layer.enabled: true
layer.effect: OpacityMask {
id: mask
maskSource: Rectangle {
height: lightGradient.height
width: lightGradient.width
radius: 180 // circle
width: parent.width
height: parent.height

// ball shape
ShapePath {
strokeWidth: 0

// shade gradient
fillGradient: RadialGradient {
centerX: lightPoint.x + lightPoint.radius
centerY: lightPoint.y + lightPoint.radius
centerRadius: controllerSize
focalX: (lightPoint.x - lightPoint.startOffset) * 0.75 + lightPoint.startOffset + lightPoint.radius
focalY: (lightPoint.y - lightPoint.startOffset) * 0.75 + lightPoint.startOffset + lightPoint.radius
focalRadius: 2
GradientStop { position: 0.00; color: "#FFCCCCCC" }
GradientStop { position: 0.05; color: "#FFAAAAAA" }
GradientStop { position: 0.50; color: "#FF0C0C0C" }
}
}
}

Rectangle {
id: lightPoint

property double startOffset : (parent.width - width) * 0.5
// ball circle path
PathRectangle {
x: 0
y: 0
width: controllerSize
height: controllerSize
radius: controllerSize * 0.5 // circle shape
}
}

x: startOffset
y: startOffset
width: controllerRadius / 6
height: width
radius: 180 // circle
color: "white"
}
// light point shape
ShapePath {
strokeWidth: 0

// glow gradient
fillGradient: RadialGradient {
centerX: lightPoint.x + centerRadius
centerY: lightPoint.y + centerRadius
centerRadius: lightPoint.radius
focalX: centerX
focalY: centerY
GradientStop { position: 0.4; color: "#FFFFFFFF" }
GradientStop { position: 0.75; color: "#33FFFFFF" }
GradientStop { position: 1.0; color: "#00FFFFFF" }
}

Glow {
anchors.fill: lightPoint
radius: controllerRadius / 5
samples: 17
color: "white"
source: lightPoint
// point circle path
PathRectangle {
id: lightPoint
readonly property double startOffset : (lightBallController.width - width) * 0.5
x: startOffset
y: startOffset
width: controllerRadius * 0.4
height: width
radius: width * 0.5 // circle shape
}
}
}

MouseArea {
Expand Down
102 changes: 78 additions & 24 deletions meshroom/ui/qml/Viewer/Viewer2D.qml
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ FocusScope {
xOrigin: imgContainer.width / 2
yOrigin: imgContainer.height / 2

property var activeNode: _reconstruction ? _reconstruction.activeNodes.get('PhotometricStereo').node : null
property var selectedNode: _reconstruction ? _reconstruction.selectedNode : null
property var vp: _reconstruction ? getViewpoint(_reconstruction.selectedViewId) : null
property url sourcePath: getAlbedoFile()
property url normalPath: getNormalFile()
Expand All @@ -652,21 +652,39 @@ FocusScope {
property int previousOrientationTag: 1

function getAlbedoFile() {

if(vp && activeNode && activeNode.hasAttribute("albedo")) {
return Filepath.stringToUrl(Filepath.resolve(activeNode.attribute("albedo").value, vp))
// get the image file from an external URL
if (useExternal) {
var externalFile = Filepath.urlToString(sourceExternal)
if(externalFile.includes("_normals"))
return Filepath.stringToUrl(externalFile.replace("_normals", "_albedo"))
return sourceExternal
}

// get the image file from selected node albedo attribute
if(vp && selectedNode && selectedNode.hasAttribute("albedo"))
return Filepath.stringToUrl(Filepath.resolve(selectedNode.attribute("albedo").value, vp))

return getImageFile()
// no valid image file, return empty url
return ""
}

function getNormalFile() {

if(vp && activeNode && activeNode.hasAttribute("normals")) {
return Filepath.stringToUrl(Filepath.resolve(activeNode.attribute("normals").value, vp))
// get the image file from an external URL
if (useExternal) {
var externalFile = Filepath.urlToString(sourceExternal)
if(externalFile.includes("_normals"))
return sourceExternal
if(externalFile.includes("_albedo"))
return Filepath.stringToUrl(externalFile.replace("_albedo", "_normals"))
return "" // invalid external file
}

return getImageFile()
// get the image file from selected node normals attribute
if(vp && selectedNode && selectedNode.hasAttribute("normals"))
return Filepath.stringToUrl(Filepath.resolve(selectedNode.attribute("normals").value, vp))

// no valid image file, return empty url
return ""
}

onWidthChanged: {
Expand Down Expand Up @@ -713,14 +731,14 @@ FocusScope {
'gamma': Qt.binding(function() { return hdrImageToolbar.gammaValue }),
'gain': Qt.binding(function() { return hdrImageToolbar.gainValue }),
'channelModeString': Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
'baseColor': Qt.binding(function() { return phongImageViewerToolbar.baseColorValue }),
'textureOpacity': Qt.binding(function() { return phongImageViewerToolbar.textureOpacityValue }),
'ka': Qt.binding(function() { return phongImageViewerToolbar.kaValue }),
'kd': Qt.binding(function() { return phongImageViewerToolbar.kdValue }),
'ks': Qt.binding(function() { return phongImageViewerToolbar.ksValue }),
'shininess': Qt.binding(function() { return phongImageViewerToolbar.shininessValue }),
'lightYaw': Qt.binding(function() { return -directionalLightPane.lightYawValue }), // left handed coordinate system
'lightPitch': Qt.binding(function() { return directionalLightPane.lightPitchValue }),
'baseColor': Qt.binding(function() { return phongImageViewerToolbarLoader.item !== null ? phongImageViewerToolbarLoader.item.baseColorValue : "#ffffff" }),
'textureOpacity': Qt.binding(function() { return phongImageViewerToolbarLoader.item !== null ? phongImageViewerToolbarLoader.item.textureOpacityValue : 0.0}),
'ka': Qt.binding(function() { return phongImageViewerToolbarLoader.item !== null ? phongImageViewerToolbarLoader.item.kaValue : 0.0 }),
'kd': Qt.binding(function() { return phongImageViewerToolbarLoader.item !== null ? phongImageViewerToolbarLoader.item.kdValue : 0.0 }),
'ks': Qt.binding(function() { return phongImageViewerToolbarLoader.item !== null ? phongImageViewerToolbarLoader.item.ksValue : 0.0 }),
'shininess': Qt.binding(function() { return phongImageViewerToolbarLoader.item !== null ? phongImageViewerToolbarLoader.item.shininessValue : 0.0 }),
'lightYaw': Qt.binding(function() { return directionalLightPaneLoader.item !== null ? -directionalLightPaneLoader.item.lightYawValue : 0.0 }), // left handed coordinate system
'lightPitch': Qt.binding(function() { return directionalLightPaneLoader.item !== null ? directionalLightPaneLoader.item.lightPitchValue : 0.0 }),
})
} else {
// Forcing the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
Expand Down Expand Up @@ -1062,6 +1080,38 @@ FocusScope {
}
}
}
FloatingPane {
Layout.fillWidth: true
Layout.fillHeight: false
Layout.preferredHeight: childrenRect.height
visible: phongImageViewerLoader.item !== null &&
phongImageViewerLoader.item.imageStatus === Image.Error &&
phongImageViewerLoader.sourcePath != ""
Layout.alignment: Qt.AlignHCenter
RowLayout {
anchors.fill: parent
Label {
font.pointSize: 8
text: {
if (phongImageViewerLoader.item !== null) {
switch (phongImageViewerLoader.item.status) {
case 2: // AliceVision.PhongImageViewer.EStatus.MISSING_FILE
return "Invalid / Missing File(s)"
case 4: // AliceVision.PhongImageViewer.EStatus.LOADING_ERROR
return "Error"
default:
return ""
}
}
return ""
}
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
}
}
}

Item {
id: imgPlaceholder
Expand Down Expand Up @@ -1349,25 +1399,29 @@ FocusScope {
}
}

PhongImageViewerToolbar {
id: phongImageViewerToolbar

Loader {
id: phongImageViewerToolbarLoader
active: phongImageViewerLoader.status === Loader.Ready
anchors {
bottom: parent.bottom
left: parent.left
margins: 2
}
visible: root.aliceVisionPluginAvailable && phongImageViewerLoader.active
sourceComponent: PhongImageViewerToolbar {
}
}

DirectionalLightPane {
id: directionalLightPane
Loader {
id: directionalLightPaneLoader
active: phongImageViewerToolbarLoader.status === Loader.Ready
anchors {
bottom: parent.bottom
right: parent.right
margins: 2
}
visible: root.aliceVisionPluginAvailable && phongImageViewerLoader.active && phongImageViewerToolbar.displayLightController
sourceComponent: DirectionalLightPane {
visible: phongImageViewerToolbarLoader.item !== null && phongImageViewerToolbarLoader.item.displayLightController
}
}
}

Expand Down
Loading