feat: use logarithmic conversion for lithophanes

This commit is contained in:
Tim Kuipers 2019-05-20 12:10:18 +02:00
parent ba878ccff0
commit 3168328750
3 changed files with 40 additions and 4 deletions

View file

@ -143,6 +143,28 @@ UM.Dialog
} }
} }
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","For lithophanes a logarithmic function is more appropriate for most materials. For height maps the pixel values correspond to heights linearly.")
Row {
width: parent.width
Label {
text: "Conversion"
width: 150 * screenScaleFactor
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
id: conversion
objectName: "Conversion"
model: [ catalog.i18nc("@item:inlistbox","Logarithmic"), catalog.i18nc("@item:inlistbox","Linear") ]
width: 180 * screenScaleFactor
onCurrentIndexChanged: { manager.onConvertFunctionChanged(currentIndex) }
}
}
}
UM.TooltipArea { UM.TooltipArea {
Layout.fillWidth:true Layout.fillWidth:true
height: childrenRect.height height: childrenRect.height

View file

@ -3,6 +3,8 @@
import numpy import numpy
import math
from PyQt5.QtGui import QImage, qRed, qGreen, qBlue from PyQt5.QtGui import QImage, qRed, qGreen, qBlue
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
@ -46,9 +48,9 @@ class ImageReader(MeshReader):
def _read(self, file_name): def _read(self, file_name):
size = max(self._ui.getWidth(), self._ui.getDepth()) size = max(self._ui.getWidth(), self._ui.getDepth())
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher) return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher, self._ui.use_logarithmic_function)
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher): def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher, use_logarithmic_function):
scene_node = SceneNode() scene_node = SceneNode()
mesh = MeshBuilder() mesh = MeshBuilder()
@ -124,8 +126,14 @@ class ImageReader(MeshReader):
Job.yieldThread() Job.yieldThread()
height_data *= scale_vector.y if use_logarithmic_function:
height_data += base_height min_luminance = 2.0 ** (peak_height - base_height)
for (y, x) in numpy.ndindex(height_data.shape):
mapped_luminance = min_luminance + (1.0 - min_luminance) * height_data[y, x]
height_data[y, x] = peak_height - math.log(mapped_luminance, 2)
else:
height_data *= scale_vector.y
height_data += base_height
heightmap_face_count = 2 * height_minus_one * width_minus_one heightmap_face_count = 2 * height_minus_one * width_minus_one
total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2 total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2

View file

@ -34,6 +34,7 @@ class ImageReaderUI(QObject):
self.peak_height = 2.5 self.peak_height = 2.5
self.smoothing = 1 self.smoothing = 1
self.lighter_is_higher = False; self.lighter_is_higher = False;
self.use_logarithmic_function = False;
self._ui_lock = threading.Lock() self._ui_lock = threading.Lock()
self._cancelled = False self._cancelled = False
@ -144,3 +145,8 @@ class ImageReaderUI(QObject):
@pyqtSlot(int) @pyqtSlot(int)
def onImageColorInvertChanged(self, value): def onImageColorInvertChanged(self, value):
self.lighter_is_higher = (value == 1) self.lighter_is_higher = (value == 1)
@pyqtSlot(int)
def onConvertFunctionChanged(self, value):
self.use_logarithmic_function = (value == 0)