diff --git a/ACKNOWLEDGEMENTS.html b/ACKNOWLEDGEMENTS.html
index 28ebb99e..66518d47 100644
--- a/ACKNOWLEDGEMENTS.html
+++ b/ACKNOWLEDGEMENTS.html
@@ -1345,4 +1345,22 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode
** $QT_END_LICENSE$
**
****************************************************************************/
-
\ No newline at end of file
+
+
+
Qt-Color-Widgets
+
+ Linking this library statically or dynamically with other modules is making a
+ combined work based on this library. Thus, the terms and conditions of the
+ GNU Lesser General Public License version 3 cover the whole combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to combine this library with independent
+ modules to produce an executable, and to copy and distribute the resulting
+ executable under terms of any of the GNU General Public licenses, as published
+ by the Free Software Foundation, provided that you also meet,
+ for each linked independent module, the terms and conditions of the license of
+ that module. An independent module is a module which is not derived from or
+ based on this library. If you modify this library, you may extend this
+ exception to your version of the library, but you are not obliged to do so.
+ If you do not wish to do so, delete this exception statement from your version.
+
diff --git a/dust3d.pro b/dust3d.pro
index f79619a6..a0b23060 100644
--- a/dust3d.pro
+++ b/dust3d.pro
@@ -132,6 +132,7 @@ DEFINES += NOMINMAX
include(thirdparty/QtAwesome/QtAwesome/QtAwesome.pri)
include(thirdparty/qtsingleapplication/src/qtsingleapplication.pri)
+include(thirdparty/Qt-Color-Widgets/color_widgets.pri)
INCLUDEPATH += src
@@ -443,8 +444,11 @@ HEADERS += src/intnumberwidget.h
SOURCES += src/imagepreviewwidget.cpp
HEADERS += src/imagepreviewwidget.h
-SOURCES += src/mousepicker.cpp
-HEADERS += src/mousepicker.h
+SOURCES += src/vertexcolorpainter.cpp
+HEADERS += src/vertexcolorpainter.h
+
+SOURCES += src/voxelgrid.cpp
+HEADERS += src/voxelgrid.h
SOURCES += src/paintmode.cpp
HEADERS += src/paintmode.h
diff --git a/shaders/default.core.frag b/shaders/default.core.frag
index a4c09eae..5014ea7b 100644
--- a/shaders/default.core.frag
+++ b/shaders/default.core.frag
@@ -573,16 +573,16 @@ void main()
lights[0].type = TYPE_POINT;
lights[0].position = firstLightPos;
lights[0].color = vec3(1.0, 1.0, 1.0);
- lights[0].intensity = 3.0;
- lights[0].constantAttenuation = 0.0;
+ lights[0].intensity = 1.0;
+ lights[0].constantAttenuation = 1.0;
lights[0].linearAttenuation = 0.0;
- lights[0].quadraticAttenuation = 0.0;
+ lights[0].quadraticAttenuation = 0.0025;
// Fill light
lights[1].type = TYPE_POINT;
lights[1].position = secondLightPos;
lights[1].color = vec3(1.0, 1.0, 1.0);
- lights[1].intensity = 1.0;
+ lights[1].intensity = 0.1;
lights[1].constantAttenuation = 0.0;
lights[1].linearAttenuation = 0.0;
lights[1].quadraticAttenuation = 0.0;
@@ -591,7 +591,7 @@ void main()
lights[2].type = TYPE_POINT;
lights[2].position = thirdLightPos;
lights[2].color = vec3(1.0, 1.0, 1.0);
- lights[2].intensity = 0.5;
+ lights[2].intensity = 0.05;
lights[2].constantAttenuation = 0.0;
lights[2].linearAttenuation = 0.0;
lights[2].quadraticAttenuation = 0.0;
@@ -635,8 +635,8 @@ void main()
ambientOcclusion = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).r;
}
+ roughness = min(0.99, roughness);
if (environmentIrradianceMapEnabled != 1) {
- roughness = min(0.99, roughness);
metalness = min(0.99, metalness);
}
diff --git a/src/document.cpp b/src/document.cpp
index 917481bc..32c1c62b 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -17,7 +17,6 @@
#include "motionsgenerator.h"
#include "skeletonside.h"
#include "scriptrunner.h"
-#include "mousepicker.h"
#include "imageforever.h"
#include "contourtopartconverter.h"
@@ -41,10 +40,12 @@ Document::Document() :
rigType(RigType::None),
weldEnabled(true),
polyCount(PolyCount::Original),
+ brushColor(Qt::white),
// private
m_isResultMeshObsolete(false),
m_meshGenerator(nullptr),
m_resultMesh(nullptr),
+ m_paintedMesh(nullptr),
m_resultMeshCutFaceTransforms(nullptr),
m_resultMeshNodesCutFaces(nullptr),
m_isMeshGenerationSucceed(true),
@@ -73,11 +74,12 @@ Document::Document() :
m_nextMeshGenerationId(1),
m_scriptRunner(nullptr),
m_isScriptResultObsolete(false),
- m_mousePicker(nullptr),
+ m_vertexColorPainter(nullptr),
m_isMouseTargetResultObsolete(false),
m_paintMode(PaintMode::None),
- m_mousePickRadius(0.2),
- m_saveNextPaintSnapshot(false)
+ m_mousePickRadius(0.05),
+ m_saveNextPaintSnapshot(false),
+ m_vertexColorVoxelGrid(nullptr)
{
connect(&Preferences::instance(), &Preferences::partColorChanged, this, &Document::applyPreferencePartColorChange);
connect(&Preferences::instance(), &Preferences::flatShadingChanged, this, &Document::applyPreferenceFlatShadingChange);
@@ -103,6 +105,7 @@ void Document::applyPreferenceTextureSizeChange()
Document::~Document()
{
delete m_resultMesh;
+ delete m_paintedMesh;
delete m_resultMeshCutFaceTransforms;
delete m_resultMeshNodesCutFaces;
delete m_postProcessedOutcome;
@@ -1029,7 +1032,7 @@ void Document::setPaintMode(PaintMode mode)
m_paintMode = mode;
emit paintModeChanged();
- doPickMouseTarget();
+ paintVertexColors();
}
void Document::joinNodeAndNeiborsToGroup(std::vector *group, QUuid nodeId, std::set *visitMap, QUuid noUseEdgeId)
@@ -1170,6 +1173,10 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId
part["color"] = partIt.second.color.name(QColor::HexArgb);
if (partIt.second.colorSolubilityAdjusted())
part["colorSolubility"] = QString::number(partIt.second.colorSolubility);
+ if (partIt.second.metalnessAdjusted())
+ part["metalness"] = QString::number(partIt.second.metalness);
+ if (partIt.second.roughnessAdjusted())
+ part["roughness"] = QString::number(partIt.second.roughness);
if (partIt.second.deformThicknessAdjusted())
part["deformThickness"] = QString::number(partIt.second.deformThickness);
if (partIt.second.deformWidthAdjusted())
@@ -1590,6 +1597,12 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou
const auto &colorSolubilityIt = partKv.second.find("colorSolubility");
if (colorSolubilityIt != partKv.second.end())
part.colorSolubility = colorSolubilityIt->second.toFloat();
+ const auto &metalnessIt = partKv.second.find("metalness");
+ if (metalnessIt != partKv.second.end())
+ part.metalness = metalnessIt->second.toFloat();
+ const auto &roughnessIt = partKv.second.find("roughness");
+ if (roughnessIt != partKv.second.end())
+ part.roughness = roughnessIt->second.toFloat();
const auto &deformThicknessIt = partKv.second.find("deformThickness");
if (deformThicknessIt != partKv.second.end())
part.setDeformThickness(deformThicknessIt->second.toFloat());
@@ -1905,6 +1918,14 @@ Model *Document::takeResultMesh()
return resultMesh;
}
+Model *Document::takePaintedMesh()
+{
+ if (nullptr == m_paintedMesh)
+ return nullptr;
+ Model *paintedMesh = new Model(*m_paintedMesh);
+ return paintedMesh;
+}
+
bool Document::isMeshGenerationSucceed()
{
return m_isMeshGenerationSucceed;
@@ -2205,12 +2226,12 @@ void Document::pickMouseTarget(const QVector3D &nearPosition, const QVector3D &f
m_mouseRayNear = nearPosition;
m_mouseRayFar = farPosition;
- doPickMouseTarget();
+ paintVertexColors();
}
-void Document::doPickMouseTarget()
+void Document::paintVertexColors()
{
- if (nullptr != m_mousePicker) {
+ if (nullptr != m_vertexColorPainter) {
m_isMouseTargetResultObsolete = true;
return;
}
@@ -2225,44 +2246,41 @@ void Document::doPickMouseTarget()
//qDebug() << "Mouse picking..";
QThread *thread = new QThread;
- m_mousePicker = new MousePicker(*m_currentOutcome, m_mouseRayNear, m_mouseRayFar);
-
- std::map paintImages;
- for (const auto &it: partMap) {
- if (!it.second.deformMapImageId.isNull()) {
- paintImages[it.first] = it.second.deformMapImageId;
- }
- }
+ m_vertexColorPainter = new VertexColorPainter(*m_currentOutcome, m_mouseRayNear, m_mouseRayFar);
+ m_vertexColorPainter->setBrushColor(brushColor);
+ m_vertexColorPainter->setBrushMetalness(brushMetalness);
+ m_vertexColorPainter->setBrushRoughness(brushRoughness);
if (SkeletonDocumentEditMode::Paint == editMode) {
- m_mousePicker->setPaintImages(paintImages);
- m_mousePicker->setPaintMode(m_paintMode);
- m_mousePicker->setRadius(m_mousePickRadius);
- m_mousePicker->setMaskNodeIds(m_mousePickMaskNodeIds);
+ if (nullptr == m_vertexColorVoxelGrid) {
+ m_vertexColorVoxelGrid = new VoxelGrid();
+ }
+ m_vertexColorPainter->setVoxelGrid(m_vertexColorVoxelGrid);
+ m_vertexColorPainter->setPaintMode(m_paintMode);
+ m_vertexColorPainter->setRadius(m_mousePickRadius);
+ m_vertexColorPainter->setMaskNodeIds(m_mousePickMaskNodeIds);
}
- m_mousePicker->moveToThread(thread);
- connect(thread, &QThread::started, m_mousePicker, &MousePicker::process);
- connect(m_mousePicker, &MousePicker::finished, this, &Document::mouseTargetReady);
- connect(m_mousePicker, &MousePicker::finished, thread, &QThread::quit);
+ m_vertexColorPainter->moveToThread(thread);
+ connect(thread, &QThread::started, m_vertexColorPainter, &VertexColorPainter::process);
+ connect(m_vertexColorPainter, &VertexColorPainter::finished, this, &Document::vertexColorsReady);
+ connect(m_vertexColorPainter, &VertexColorPainter::finished, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
-void Document::mouseTargetReady()
+void Document::vertexColorsReady()
{
- m_mouseTargetPosition = m_mousePicker->targetPosition();
- const auto &changedPartIds = m_mousePicker->changedPartIds();
- for (const auto &it: m_mousePicker->resultPaintImages()) {
- const auto &partId = it.first;
- if (changedPartIds.find(partId) == changedPartIds.end())
- continue;
- const auto &imageId = it.second;
- m_intermediatePaintImageIds.insert(imageId);
- setPartDeformMapImageId(partId, imageId);
+ m_mouseTargetPosition = m_vertexColorPainter->targetPosition();
+
+ Model *model = m_vertexColorPainter->takePaintedModel();
+ if (nullptr != model) {
+ delete m_paintedMesh;
+ m_paintedMesh = model;
+ emit paintedMeshChanged();
}
- delete m_mousePicker;
- m_mousePicker = nullptr;
+ delete m_vertexColorPainter;
+ m_vertexColorPainter = nullptr;
if (!m_isMouseTargetResultObsolete && m_saveNextPaintSnapshot) {
m_saveNextPaintSnapshot = false;
@@ -3064,6 +3082,36 @@ void Document::setPartColorSolubility(QUuid partId, float solubility)
emit skeletonChanged();
}
+void Document::setPartMetalness(QUuid partId, float metalness)
+{
+ auto part = partMap.find(partId);
+ if (part == partMap.end()) {
+ qDebug() << "Part not found:" << partId;
+ return;
+ }
+ if (qFuzzyCompare(part->second.metalness, metalness))
+ return;
+ part->second.metalness = metalness;
+ part->second.dirty = true;
+ emit partMetalnessChanged(partId);
+ emit skeletonChanged();
+}
+
+void Document::setPartRoughness(QUuid partId, float roughness)
+{
+ auto part = partMap.find(partId);
+ if (part == partMap.end()) {
+ qDebug() << "Part not found:" << partId;
+ return;
+ }
+ if (qFuzzyCompare(part->second.roughness, roughness))
+ return;
+ part->second.roughness = roughness;
+ part->second.dirty = true;
+ emit partRoughnessChanged(partId);
+ emit skeletonChanged();
+}
+
void Document::setPartHollowThickness(QUuid partId, float hollowThickness)
{
auto part = partMap.find(partId);
@@ -4086,19 +4134,11 @@ void Document::startPaint(void)
void Document::stopPaint(void)
{
- if (m_mousePicker || m_isMouseTargetResultObsolete) {
+ if (m_vertexColorPainter || m_isMouseTargetResultObsolete) {
m_saveNextPaintSnapshot = true;
return;
}
- saveSnapshot();
- for (const auto &it: partMap) {
- m_intermediatePaintImageIds.erase(it.second.deformMapImageId);
- }
- for (const auto &it: m_intermediatePaintImageIds) {
- //qDebug() << "Remove intermediate image:" << it;
- ImageForever::remove(it);
- }
- m_intermediatePaintImageIds.clear();
+ //saveSnapshot();
}
void Document::setMousePickMaskNodeIds(const std::set &nodeIds)
diff --git a/src/document.h b/src/document.h
index 2efd8bc5..30dd674d 100644
--- a/src/document.h
+++ b/src/document.h
@@ -31,11 +31,12 @@
#include "proceduralanimation.h"
#include "componentlayer.h"
#include "clothforce.h"
+#include "voxelgrid.h"
+#include "vertexcolorpainter.h"
class MaterialPreviewsGenerator;
class MotionsGenerator;
class ScriptRunner;
-class MousePicker;
class HistoryItem
{
@@ -437,6 +438,7 @@ signals:
void edgeReversed(QUuid edgeId);
void partPreviewChanged(QUuid partId);
void resultMeshChanged();
+ void paintedMeshChanged();
void turnaroundChanged();
void editModeChanged();
void paintModeChanged();
@@ -466,6 +468,8 @@ signals:
void partChamferStateChanged(QUuid partId);
void partTargetChanged(QUuid partId);
void partColorSolubilityChanged(QUuid partId);
+ void partMetalnessChanged(QUuid partId);
+ void partRoughnessChanged(QUuid partId);
void partHollowThicknessChanged(QUuid partId);
void partCountershadeStateChanged(QUuid partId);
void partGridStateChanged(QUuid partId);
@@ -537,6 +541,9 @@ public: // need initialize
RigType rigType;
bool weldEnabled;
PolyCount polyCount;
+ QColor brushColor;
+ float brushMetalness = Model::m_defaultMetalness;
+ float brushRoughness = Model::m_defaultRoughness;
public:
Document();
~Document();
@@ -576,6 +583,7 @@ public:
const Pose *findPose(QUuid poseId) const;
const Motion *findMotion(QUuid motionId) const;
Model *takeResultMesh();
+ Model *takePaintedMesh();
bool isMeshGenerationSucceed();
Model *takeResultTextureMesh();
Model *takeResultRigWeightMesh();
@@ -646,8 +654,8 @@ public slots:
void generateMotions();
void motionsReady();
void pickMouseTarget(const QVector3D &nearPosition, const QVector3D &farPosition);
- void doPickMouseTarget();
- void mouseTargetReady();
+ void paintVertexColors();
+ void vertexColorsReady();
void setPartLockState(QUuid partId, bool locked);
void setPartVisibleState(QUuid partId, bool visible);
void setPartSubdivState(QUuid partId, bool subdived);
@@ -668,6 +676,8 @@ public slots:
void setPartChamferState(QUuid partId, bool chamfered);
void setPartTarget(QUuid partId, PartTarget target);
void setPartColorSolubility(QUuid partId, float solubility);
+ void setPartMetalness(QUuid partId, float metalness);
+ void setPartRoughness(QUuid partId, float roughness);
void setPartHollowThickness(QUuid partId, float hollowThickness);
void setPartCountershaded(QUuid partId, bool countershaded);
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
@@ -774,6 +784,7 @@ private: // need initialize
bool m_isResultMeshObsolete;
MeshGenerator *m_meshGenerator;
Model *m_resultMesh;
+ Model *m_paintedMesh;
std::map *m_resultMeshCutFaceTransforms;
std::map> *m_resultMeshNodesCutFaces;
bool m_isMeshGenerationSucceed;
@@ -805,11 +816,12 @@ private: // need initialize
std::map> m_mergedVariables;
ScriptRunner *m_scriptRunner;
bool m_isScriptResultObsolete;
- MousePicker *m_mousePicker;
+ VertexColorPainter *m_vertexColorPainter;
bool m_isMouseTargetResultObsolete;
PaintMode m_paintMode;
float m_mousePickRadius;
bool m_saveNextPaintSnapshot;
+ VoxelGrid *m_vertexColorVoxelGrid;
private:
static unsigned long m_maxSnapshot;
std::deque m_undoItems;
@@ -823,7 +835,6 @@ private:
QString m_scriptConsoleLog;
QString m_script;
std::set m_mousePickMaskNodeIds;
- std::set m_intermediatePaintImageIds;
};
#endif
diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp
index b80ec8f7..b6e53c40 100644
--- a/src/documentwindow.cpp
+++ b/src/documentwindow.cpp
@@ -162,7 +162,8 @@ DocumentWindow::DocumentWindow() :
m_exportPreviewWidget(nullptr),
m_preferencesWidget(nullptr),
m_isLastMeshGenerationSucceed(true),
- m_currentUpdatedMeshId(0)
+ m_currentUpdatedMeshId(0),
+ m_colorWheelWidget(nullptr)
{
QObject::connect((QtSingleApplication *)QGuiApplication::instance(),
&QtSingleApplication::messageReceived, this, [this](const QString &message) {
@@ -201,9 +202,9 @@ DocumentWindow::DocumentWindow() :
//markerButton->setToolTip(tr("Marker pen"));
//Theme::initAwesomeButton(markerButton);
- QPushButton *paintButton = new QPushButton(QChar(fa::paintbrush));
- paintButton->setToolTip(tr("Paint brush"));
- Theme::initAwesomeButton(paintButton);
+ //QPushButton *paintButton = new QPushButton(QChar(fa::paintbrush));
+ //paintButton->setToolTip(tr("Paint brush"));
+ //Theme::initAwesomeButton(paintButton);
//QPushButton *dragButton = new QPushButton(QChar(fa::handrocko));
//dragButton->setToolTip(tr("Enter drag mode"));
@@ -269,6 +270,10 @@ DocumentWindow::DocumentWindow() :
updateRegenerateIconAndTips(regenerateButton, m_document->isMeshGenerationSucceed());
generatePartPreviewImages();
});
+ connect(m_document, &Document::paintedMeshChanged, [=]() {
+ auto paintedMesh = m_document->takePaintedMesh();
+ m_modelRenderWidget->updateMesh(paintedMesh);
+ });
connect(m_document, &Document::postProcessing, this, [=]() {
regenerateButton->showSpinner(true);
});
@@ -287,7 +292,7 @@ DocumentWindow::DocumentWindow() :
toolButtonLayout->addWidget(addButton);
toolButtonLayout->addWidget(selectButton);
//toolButtonLayout->addWidget(markerButton);
- toolButtonLayout->addWidget(paintButton);
+ //toolButtonLayout->addWidget(paintButton);
//toolButtonLayout->addWidget(dragButton);
toolButtonLayout->addWidget(zoomInButton);
toolButtonLayout->addWidget(zoomOutButton);
@@ -392,16 +397,80 @@ DocumentWindow::DocumentWindow() :
setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East);
- QDockWidget *partTreeDocker = new QDockWidget(tr("Parts"), this);
- partTreeDocker->setAllowedAreas(Qt::RightDockWidgetArea);
- m_partTreeWidget = new PartTreeWidget(m_document, partTreeDocker);
- partTreeDocker->setWidget(m_partTreeWidget);
- addDockWidget(Qt::RightDockWidgetArea, partTreeDocker);
- //connect(partTreeDocker, &QDockWidget::topLevelChanged, [=](bool topLevel) {
- // Q_UNUSED(topLevel);
- // for (const auto &part: m_document->partMap)
- // m_partTreeWidget->partPreviewChanged(part.first);
- //});
+ QDockWidget *partsDocker = new QDockWidget(tr("Parts"), this);
+ partsDocker->setAllowedAreas(Qt::RightDockWidgetArea);
+ m_colorWheelWidget = new color_widgets::ColorWheel(nullptr);
+ m_colorWheelWidget->setContentsMargins(0, 5, 0, 5);
+ m_colorWheelWidget->hide();
+ m_document->brushColor = m_colorWheelWidget->color();
+ connect(m_colorWheelWidget, &color_widgets::ColorWheel::colorChanged, this, [=](QColor color) {
+ m_document->brushColor = color;
+ });
+
+ FloatNumberWidget *metalnessWidget = new FloatNumberWidget;
+ metalnessWidget->setSliderFixedWidth(Theme::sidebarPreferredWidth * 0.4);
+ metalnessWidget->setItemName(tr("Metallic"));
+ metalnessWidget->setRange(0.0, 1.0);
+ metalnessWidget->setValue(m_document->brushMetalness);
+
+ connect(metalnessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
+ m_document->brushMetalness = value;
+ });
+
+ QPushButton *metalnessEraser = new QPushButton(QChar(fa::eraser));
+ Theme::initAwesomeToolButtonWithoutFont(metalnessEraser);
+
+ connect(metalnessEraser, &QPushButton::clicked, [=]() {
+ metalnessWidget->setValue(Model::m_defaultMetalness);
+ });
+
+ QHBoxLayout *metalnessLayout = new QHBoxLayout;
+ metalnessLayout->addWidget(metalnessEraser);
+ metalnessLayout->addWidget(metalnessWidget);
+
+ FloatNumberWidget *roughnessWidget = new FloatNumberWidget;
+ roughnessWidget->setSliderFixedWidth(Theme::sidebarPreferredWidth * 0.35);
+ roughnessWidget->setItemName(tr("Roughness"));
+ roughnessWidget->setRange(0.0, 1.0);
+ roughnessWidget->setValue(m_document->brushRoughness);
+
+ connect(roughnessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
+ m_document->brushRoughness = value;
+ });
+
+ QPushButton *roughnessEraser = new QPushButton(QChar(fa::eraser));
+ Theme::initAwesomeToolButtonWithoutFont(roughnessEraser);
+
+ connect(roughnessEraser, &QPushButton::clicked, [=]() {
+ roughnessWidget->setValue(Model::m_defaultRoughness);
+ });
+
+ QHBoxLayout *roughnessLayout = new QHBoxLayout;
+ roughnessLayout->addWidget(roughnessEraser);
+ roughnessLayout->addWidget(roughnessWidget);
+
+ QWidget *metalnessAndRoughnessWidget = new QWidget;
+ QVBoxLayout *metalnessAndRoughnessLayout = new QVBoxLayout;
+ metalnessAndRoughnessLayout->addLayout(metalnessLayout);
+ metalnessAndRoughnessLayout->addLayout(roughnessLayout);
+ metalnessAndRoughnessWidget->setLayout(metalnessAndRoughnessLayout);
+ metalnessAndRoughnessWidget->hide();
+
+ connect(m_document, &Document::editModeChanged, this, [=]() {
+ m_colorWheelWidget->setVisible(SkeletonDocumentEditMode::Paint == m_document->editMode);
+ metalnessAndRoughnessWidget->setVisible(SkeletonDocumentEditMode::Paint == m_document->editMode);
+ });
+
+ m_partTreeWidget = new PartTreeWidget(m_document, nullptr);
+ QWidget *partsWidget = new QWidget(partsDocker);
+ QVBoxLayout *partsLayout = new QVBoxLayout;
+ partsLayout->setContentsMargins(0, 0, 0, 0);
+ partsLayout->addWidget(m_colorWheelWidget);
+ partsLayout->addWidget(metalnessAndRoughnessWidget);
+ partsLayout->addWidget(m_partTreeWidget);
+ partsWidget->setLayout(partsLayout);
+ partsDocker->setWidget(partsWidget);
+ addDockWidget(Qt::RightDockWidgetArea, partsDocker);
QDockWidget *materialDocker = new QDockWidget(tr("Materials"), this);
materialDocker->setAllowedAreas(Qt::RightDockWidgetArea);
@@ -453,13 +522,13 @@ DocumentWindow::DocumentWindow() :
scriptDocker->setWidget(scriptWidget);
addDockWidget(Qt::RightDockWidgetArea, scriptDocker);
- tabifyDockWidget(partTreeDocker, materialDocker);
+ tabifyDockWidget(partsDocker, materialDocker);
tabifyDockWidget(materialDocker, rigDocker);
tabifyDockWidget(rigDocker, poseDocker);
tabifyDockWidget(poseDocker, motionDocker);
tabifyDockWidget(motionDocker, scriptDocker);
- partTreeDocker->raise();
+ partsDocker->raise();
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->setSpacing(0);
@@ -829,8 +898,8 @@ DocumentWindow::DocumentWindow() :
m_showPartsListAction = new QAction(tr("Parts"), this);
connect(m_showPartsListAction, &QAction::triggered, [=]() {
- partTreeDocker->show();
- partTreeDocker->raise();
+ partsDocker->show();
+ partsDocker->raise();
});
m_windowMenu->addAction(m_showPartsListAction);
@@ -955,9 +1024,9 @@ DocumentWindow::DocumentWindow() :
// m_document->setEditMode(SkeletonDocumentEditMode::Mark);
//});
- connect(paintButton, &QPushButton::clicked, [=]() {
- m_document->setEditMode(SkeletonDocumentEditMode::Paint);
- });
+ //connect(paintButton, &QPushButton::clicked, [=]() {
+ // m_document->setEditMode(SkeletonDocumentEditMode::Paint);
+ //});
//connect(dragButton, &QPushButton::clicked, [=]() {
// m_document->setEditMode(SkeletonDocumentEditMode::Drag);
@@ -992,8 +1061,8 @@ DocumentWindow::DocumentWindow() :
m_partListDockerVisibleSwitchConnection = connect(m_document, &Document::skeletonChanged, [=]() {
if (m_graphicsWidget->hasItems()) {
- if (partTreeDocker->isHidden())
- partTreeDocker->show();
+ if (partsDocker->isHidden())
+ partsDocker->show();
disconnect(m_partListDockerVisibleSwitchConnection);
}
});
@@ -1147,6 +1216,8 @@ DocumentWindow::DocumentWindow() :
connect(m_document, &Document::partHollowThicknessChanged, m_partTreeWidget, &PartTreeWidget::partHollowThicknessChanged);
connect(m_document, &Document::partMaterialIdChanged, m_partTreeWidget, &PartTreeWidget::partMaterialIdChanged);
connect(m_document, &Document::partColorSolubilityChanged, m_partTreeWidget, &PartTreeWidget::partColorSolubilityChanged);
+ connect(m_document, &Document::partMetalnessChanged, m_partTreeWidget, &PartTreeWidget::partMetalnessChanged);
+ connect(m_document, &Document::partRoughnessChanged, m_partTreeWidget, &PartTreeWidget::partRoughnessChanged);
connect(m_document, &Document::partCountershadeStateChanged, m_partTreeWidget, &PartTreeWidget::partCountershadeStateChanged);
connect(m_document, &Document::partTargetChanged, m_partTreeWidget, &PartTreeWidget::partXmirrorStateChanged);
diff --git a/src/documentwindow.h b/src/documentwindow.h
index dc045e73..29c63a7d 100644
--- a/src/documentwindow.h
+++ b/src/documentwindow.h
@@ -21,6 +21,7 @@
#include "normalanddepthmapsgenerator.h"
#include "autosaver.h"
#include "partpreviewimagesgenerator.h"
+#include "QtColorWidgets/ColorWheel"
class SkeletonGraphicsWidget;
class PartTreeWidget;
@@ -116,6 +117,7 @@ private:
bool m_isLastMeshGenerationSucceed;
quint64 m_currentUpdatedMeshId;
QStringList m_waitingForExportToFilenames;
+ color_widgets::ColorWheel *m_colorWheelWidget;
private:
QString m_currentFilename;
diff --git a/src/floatnumberwidget.cpp b/src/floatnumberwidget.cpp
index 0988fdde..c7284e9c 100644
--- a/src/floatnumberwidget.cpp
+++ b/src/floatnumberwidget.cpp
@@ -34,6 +34,11 @@ FloatNumberWidget::FloatNumberWidget(QWidget *parent, bool singleLine) :
}
}
+void FloatNumberWidget::setSliderFixedWidth(float width)
+{
+ m_slider->setFixedWidth(width);
+}
+
void FloatNumberWidget::updateValueLabel(float value)
{
QString valueString = QString().sprintf("%.2f", value);
diff --git a/src/floatnumberwidget.h b/src/floatnumberwidget.h
index 1913bc26..7d841a91 100644
--- a/src/floatnumberwidget.h
+++ b/src/floatnumberwidget.h
@@ -9,10 +9,11 @@ class FloatNumberWidget : public QWidget
{
Q_OBJECT
public:
- explicit FloatNumberWidget(QWidget *parent = nullptr, bool singleLine=true);
+ explicit FloatNumberWidget(QWidget *parent=nullptr, bool singleLine=true);
void setRange(float min, float max);
float value() const;
void setItemName(const QString &name);
+ void setSliderFixedWidth(float width);
public slots:
void increaseValue();
diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp
index 85cda07c..779e8953 100644
--- a/src/meshgenerator.cpp
+++ b/src/meshgenerator.cpp
@@ -416,6 +416,16 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
if (!colorSolubilityString.isEmpty())
colorSolubility = colorSolubilityString.toFloat();
+ float metalness = 0;
+ QString metalnessString = valueOfKeyInMapOrEmpty(part, "metalness");
+ if (!metalnessString.isEmpty())
+ metalness = metalnessString.toFloat();
+
+ float roughness = 1.0;
+ QString roughnessString = valueOfKeyInMapOrEmpty(part, "roughness");
+ if (!roughnessString.isEmpty())
+ roughness = roughnessString.toFloat();
+
QUuid fillMeshFileId;
QString fillMeshString = valueOfKeyInMapOrEmpty(part, "fillMesh");
if (!fillMeshString.isEmpty()) {
@@ -538,6 +548,8 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
outcomeNode.materialId = materialId;
outcomeNode.countershaded = countershaded;
outcomeNode.colorSolubility = colorSolubility;
+ outcomeNode.metalness = metalness;
+ outcomeNode.roughness = roughness;
outcomeNode.boneMark = nodeInfo.boneMark;
if (!__mirroredByPartId.isEmpty())
outcomeNode.mirroredByPartId = QUuid(__mirroredByPartId);
diff --git a/src/model.cpp b/src/model.cpp
index cd88b9b6..3a4cc226 100644
--- a/src/model.cpp
+++ b/src/model.cpp
@@ -5,8 +5,6 @@
#include "model.h"
#include "version.h"
-#define MAX_VERTICES_PER_FACE 100
-
float Model::m_defaultMetalness = 0.0;
float Model::m_defaultRoughness = 1.0;
diff --git a/src/modelmeshbinder.cpp b/src/modelmeshbinder.cpp
index 2588bfe5..4eef98f3 100644
--- a/src/modelmeshbinder.cpp
+++ b/src/modelmeshbinder.cpp
@@ -156,18 +156,22 @@ void ModelMeshBinder::paint(ModelShaderProgram *program)
(m_hasMetalnessMap || m_hasRoughnessMap || m_hasAmbientOcclusionMap))
m_metalnessRoughnessAmbientOcclusionMap = new QOpenGLTexture(*m_mesh->metalnessRoughnessAmbientOcclusionImage());
- delete m_environmentIrradianceMap;
- m_environmentIrradianceMap = nullptr;
- delete m_environmentSpecularMap;
- m_environmentSpecularMap = nullptr;
+ //delete m_environmentIrradianceMap;
+ //m_environmentIrradianceMap = nullptr;
+ //delete m_environmentSpecularMap;
+ //m_environmentSpecularMap = nullptr;
if (program->isCoreProfile() &&
- m_environmentLightEnabled &&
- (m_hasMetalnessMap || m_hasRoughnessMap)) {
- DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds");
- m_environmentIrradianceMap = irradianceFile.createOpenGLTexture();
+ m_environmentLightEnabled/* &&
+ (m_hasMetalnessMap || m_hasRoughnessMap)*/) {
+ if (nullptr == m_environmentIrradianceMap) {
+ DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds");
+ m_environmentIrradianceMap = irradianceFile.createOpenGLTexture();
+ }
- DdsFileReader specularFile(":/resources/cedar_bridge_specular.dds");
- m_environmentSpecularMap = specularFile.createOpenGLTexture();
+ if (nullptr == m_environmentSpecularMap) {
+ DdsFileReader specularFile(":/resources/cedar_bridge_specular.dds");
+ m_environmentSpecularMap = specularFile.createOpenGLTexture();
+ }
}
{
diff --git a/src/mousepicker.cpp b/src/mousepicker.cpp
deleted file mode 100644
index c6ac617b..00000000
--- a/src/mousepicker.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "mousepicker.h"
-#include "util.h"
-#include "imageforever.h"
-
-MousePicker::MousePicker(const Outcome &outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar) :
- m_outcome(outcome),
- m_mouseRayNear(mouseRayNear),
- m_mouseRayFar(mouseRayFar)
-{
-}
-
-const std::set &MousePicker::changedPartIds()
-{
- return m_changedPartIds;
-}
-
-void MousePicker::setPaintMode(PaintMode paintMode)
-{
- m_paintMode = paintMode;
-}
-
-void MousePicker::setMaskNodeIds(const std::set &nodeIds)
-{
- m_mousePickMaskNodeIds = nodeIds;
-}
-
-void MousePicker::setRadius(float radius)
-{
- m_radius = radius;
-}
-
-MousePicker::~MousePicker()
-{
-}
-
-bool MousePicker::calculateMouseModelPosition(QVector3D &mouseModelPosition)
-{
- bool foundPosition = false;
- auto ray = (m_mouseRayNear - m_mouseRayFar).normalized();
- float minDistance2 = std::numeric_limits::max();
- for (size_t i = 0; i < m_outcome.triangles.size(); ++i) {
- const auto &triangleIndices = m_outcome.triangles[i];
- std::vector triangle = {
- m_outcome.vertices[triangleIndices[0]],
- m_outcome.vertices[triangleIndices[1]],
- m_outcome.vertices[triangleIndices[2]],
- };
- const auto &triangleNormal = m_outcome.triangleNormals[i];
- if (QVector3D::dotProduct(triangleNormal, ray) <= 0)
- continue;
- QVector3D intersection;
- if (intersectSegmentAndTriangle(m_mouseRayNear, m_mouseRayFar,
- triangle,
- triangleNormal,
- &intersection)) {
- float distance2 = (intersection - m_mouseRayNear).lengthSquared();
- if (distance2 < minDistance2) {
- mouseModelPosition = intersection;
- minDistance2 = distance2;
- foundPosition = true;
- }
- }
- }
- return foundPosition;
-}
-
-void MousePicker::pick()
-{
- if (!calculateMouseModelPosition(m_targetPosition))
- return;
-
- if (PaintMode::None == m_paintMode)
- return;
-
- float distance2 = m_radius * m_radius;
-
- for (const auto &map: m_outcome.paintMaps) {
- for (const auto &node: map.paintNodes) {
- if (!m_mousePickMaskNodeIds.empty() && m_mousePickMaskNodeIds.find(node.originNodeId) == m_mousePickMaskNodeIds.end())
- continue;
- size_t intersectedNum = 0;
- QVector3D sumOfDirection;
- QVector3D referenceDirection = (m_targetPosition - node.origin).normalized();
- float sumOfRadius = 0;
- for (const auto &vertexPosition: node.vertices) {
- // >0.866 = <30 degrees
- auto direction = (vertexPosition - node.origin).normalized();
- if (QVector3D::dotProduct(referenceDirection, direction) > 0.866 &&
- (vertexPosition - m_targetPosition).lengthSquared() <= distance2) {
- float distance = vertexPosition.distanceToPoint(m_targetPosition);
- float radius = (m_radius - distance) / node.radius;
- sumOfRadius += radius;
- sumOfDirection += direction * radius;
- ++intersectedNum;
- }
- }
- if (intersectedNum > 0) {
- float paintRadius = sumOfRadius / intersectedNum;
- QVector3D paintDirection = sumOfDirection.normalized();
- float degrees = angleInRangle360BetweenTwoVectors(node.baseNormal, paintDirection, node.direction);
- float offset = (float)node.order / map.paintNodes.size();
- m_changedPartIds.insert(map.partId);
- paintToImage(map.partId, offset, degrees / 360.0, paintRadius, PaintMode::Push == m_paintMode);
- }
- }
- }
-}
-
-void MousePicker::process()
-{
- pick();
- emit finished();
-}
-
-void MousePicker::paintToImage(const QUuid &partId, float x, float y, float radius, bool inverted)
-{
- QUuid oldImageId;
- QImage image(72, 36, QImage::Format_Grayscale8);
- image.fill(QColor(127, 127, 127));
- const auto &findImageId = m_paintImages.find(partId);
- if (findImageId != m_paintImages.end()) {
- const QImage *oldImage = ImageForever::get(findImageId->second);
- if (nullptr != oldImage) {
- if (oldImage->size() == image.size() &&
- oldImage->format() == image.format()) {
- image = *oldImage;
- }
- }
- }
- float destX = image.width() * x;
- float destY = image.height() * y;
- float destRadius = image.height() * radius;
- {
- QRadialGradient gradient(destX, destY, destRadius / 2);
- if (inverted) {
- gradient.setColorAt(0, QColor(0, 0, 0, 3));
- gradient.setColorAt(1, Qt::transparent);
- } else {
- gradient.setColorAt(0, QColor(255, 255, 255, 3));
- gradient.setColorAt(1, Qt::transparent);
- }
- QBrush brush(gradient);
- QPainter paint(&image);
- paint.setRenderHint(QPainter::HighQualityAntialiasing);
- paint.setBrush(brush);
- paint.setPen(Qt::NoPen);
- paint.drawEllipse(destX - destRadius / 2, destY - destRadius / 2, destRadius, destRadius);
- }
- QUuid imageId = ImageForever::add(&image);
- m_paintImages[partId] = imageId;
-}
-
-const QVector3D &MousePicker::targetPosition()
-{
- return m_targetPosition;
-}
-
-bool MousePicker::intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1,
- const QVector3D &pointOnPlane, const QVector3D &planeNormal,
- QVector3D *intersection)
-{
- auto u = segmentPoint1 - segmentPoint0;
- auto w = segmentPoint0 - pointOnPlane;
- auto d = QVector3D::dotProduct(planeNormal, u);
- auto n = QVector3D::dotProduct(-planeNormal, w);
- if (qAbs(d) < 0.00000001)
- return false;
- auto s = n / d;
- if (s < 0 || s > 1 || qIsNaN(s) || qIsInf(s))
- return false;
- if (nullptr != intersection)
- *intersection = segmentPoint0 + s * u;
- return true;
-}
-
-bool MousePicker::intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1,
- const std::vector &triangle,
- const QVector3D &triangleNormal,
- QVector3D *intersection)
-{
- QVector3D possibleIntersection;
- if (!intersectSegmentAndPlane(segmentPoint0, segmentPoint1,
- triangle[0], triangleNormal, &possibleIntersection)) {
- return false;
- }
- auto ray = (segmentPoint0 - segmentPoint1).normalized();
- std::vector normals;
- for (size_t i = 0; i < 3; ++i) {
- size_t j = (i + 1) % 3;
- normals.push_back(QVector3D::normal(possibleIntersection, triangle[i], triangle[j]));
- }
- if (QVector3D::dotProduct(normals[0], ray) <= 0)
- return false;
- if (QVector3D::dotProduct(normals[0], normals[1]) <= 0)
- return false;
- if (QVector3D::dotProduct(normals[0], normals[2]) <= 0)
- return false;
- if (nullptr != intersection)
- *intersection = possibleIntersection;
- return true;
-}
-
-void MousePicker::setPaintImages(const std::map &paintImages)
-{
- m_paintImages = paintImages;
-}
-
-const std::map &MousePicker::resultPaintImages()
-{
- return m_paintImages;
-}
diff --git a/src/mousepicker.h b/src/mousepicker.h
deleted file mode 100644
index cda52148..00000000
--- a/src/mousepicker.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef DUST3D_MOUSE_PICKER_H
-#define DUST3D_MOUSE_PICKER_H
-#include
-#include
-#include
-#include