Add mesh seam combine algorithm
Not enable by default, should enable the weldEnabled in the SkeletonDocument class.master
parent
a419a0fb7a
commit
6ffbdc9c7b
|
@ -194,6 +194,12 @@ HEADERS += src/posepreviewsgenerator.h
|
|||
SOURCES += src/posewidget.cpp
|
||||
HEADERS += src/posewidget.h
|
||||
|
||||
SOURCES += src/meshweldseam.cpp
|
||||
HEADERS += src/meshweldseam.h
|
||||
|
||||
SOURCES += src/advancesettingwidget.cpp
|
||||
HEADERS += src/advancesettingwidget.h
|
||||
|
||||
SOURCES += src/main.cpp
|
||||
|
||||
HEADERS += src/version.h
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#include <QFormLayout>
|
||||
#include <QCheckBox>
|
||||
#include "advancesettingwidget.h"
|
||||
#include "dust3dutil.h"
|
||||
|
||||
AdvanceSettingWidget::AdvanceSettingWidget(const SkeletonDocument *document, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_document(document)
|
||||
{
|
||||
QCheckBox *enableWeldBox = new QCheckBox();
|
||||
enableWeldBox->setChecked(document->weldEnabled);
|
||||
connect(enableWeldBox, &QCheckBox::stateChanged, this, [=]() {
|
||||
emit enableWeld(enableWeldBox->isChecked());
|
||||
});
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout;
|
||||
formLayout->addRow(tr("Weld"), enableWeldBox);
|
||||
|
||||
setLayout(formLayout);
|
||||
|
||||
connect(this, &AdvanceSettingWidget::enableWeld, document, &SkeletonDocument::enableWeld);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef ADVANCE_SETTING_WIDGET_H
|
||||
#define ADVANCE_SETTING_WIDGET_H
|
||||
#include <QDialog>
|
||||
#include "skeletondocument.h"
|
||||
|
||||
class AdvanceSettingWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void enableWeld(bool enabled);
|
||||
public:
|
||||
AdvanceSettingWidget(const SkeletonDocument *document, QWidget *parent=nullptr);
|
||||
private:
|
||||
const SkeletonDocument *m_document = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -120,6 +120,9 @@ void ExportPreviewWidget::showEvent(QShowEvent *event)
|
|||
{
|
||||
QWidget::showEvent(event);
|
||||
checkSpinner();
|
||||
if (m_document->isPostProcessResultObsolete()) {
|
||||
m_document->postProcess();
|
||||
}
|
||||
}
|
||||
|
||||
void ExportPreviewWidget::checkSpinner()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <vector>
|
||||
#include <QGuiApplication>
|
||||
#include <QElapsedTimer>
|
||||
#include <unordered_set>
|
||||
#include "meshgenerator.h"
|
||||
#include "dust3dutil.h"
|
||||
#include "skeletondocument.h"
|
||||
|
@ -9,6 +10,7 @@
|
|||
#include "theme.h"
|
||||
#include "positionmap.h"
|
||||
#include "meshquadify.h"
|
||||
#include "meshweldseam.h"
|
||||
|
||||
bool MeshGenerator::m_enableDebug = false;
|
||||
PositionMap<int> *MeshGenerator::m_forMakePositionKey = new PositionMap<int>;
|
||||
|
@ -31,12 +33,12 @@ void GeneratedCacheContext::updateComponentCombinableMesh(QString componentId, v
|
|||
MeshGenerator::MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread) :
|
||||
m_snapshot(snapshot),
|
||||
m_mesh(nullptr),
|
||||
//m_preview(nullptr),
|
||||
m_thread(thread),
|
||||
m_meshResultContext(nullptr),
|
||||
m_sharedContextWidget(nullptr),
|
||||
m_cacheContext(nullptr),
|
||||
m_smoothNormal(true)
|
||||
m_smoothNormal(true),
|
||||
m_weldEnabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +57,11 @@ void MeshGenerator::setSmoothNormal(bool smoothNormal)
|
|||
m_smoothNormal = smoothNormal;
|
||||
}
|
||||
|
||||
void MeshGenerator::setWeldEnabled(bool weldEnabled)
|
||||
{
|
||||
m_weldEnabled = weldEnabled;
|
||||
}
|
||||
|
||||
void MeshGenerator::setGeneratedCacheContext(GeneratedCacheContext *cacheContext)
|
||||
{
|
||||
m_cacheContext = cacheContext;
|
||||
|
@ -474,10 +481,8 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
|||
continue;
|
||||
bool childInverse = false;
|
||||
void *childCombinedMesh = combineComponentMesh(childId, &childInverse);
|
||||
if (smoothSeam) {
|
||||
for (const auto &positionIt: m_cacheContext->componentPositions[childId]) {
|
||||
positionsBeforeCombination.addPosition(positionIt.x(), positionIt.y(), positionIt.z(), true);
|
||||
}
|
||||
for (const auto &positionIt: m_cacheContext->componentPositions[childId]) {
|
||||
positionsBeforeCombination.addPosition(positionIt.x(), positionIt.y(), positionIt.z(), true);
|
||||
}
|
||||
for (const auto &verticesSourceIt: m_cacheContext->componentVerticesSources[childId].map()) {
|
||||
verticesSources.map()[verticesSourceIt.first] = verticesSourceIt.second;
|
||||
|
@ -502,33 +507,55 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
|||
}
|
||||
|
||||
if (nullptr != resultMesh) {
|
||||
if (smoothSeam || smoothAll) {
|
||||
int meshIdForSmooth = convertFromCombinableMesh(m_meshliteContext, resultMesh);
|
||||
std::vector<QVector3D> positionsBeforeSmooth;
|
||||
loadMeshVerticesPositions(m_meshliteContext, meshIdForSmooth, positionsBeforeSmooth);
|
||||
int meshIdForSmooth = convertFromCombinableMesh(m_meshliteContext, resultMesh);
|
||||
std::vector<QVector3D> positionsBeforeSmooth;
|
||||
loadMeshVerticesPositions(m_meshliteContext, meshIdForSmooth, positionsBeforeSmooth);
|
||||
|
||||
if (!positionsBeforeSmooth.empty()) {
|
||||
if (!positionsBeforeSmooth.empty()) {
|
||||
std::vector<int> seamVerticesIds;
|
||||
std::unordered_set<int> seamVerticesIndicies;
|
||||
|
||||
if (smoothSeam) {
|
||||
int *seamVerticesIndicies = new int[positionsBeforeSmooth.size()];
|
||||
int seamVerticesNum = 0;
|
||||
for (size_t vertexIndex = 0; vertexIndex < positionsBeforeSmooth.size(); vertexIndex++) {
|
||||
const auto &oldPosition = positionsBeforeSmooth[vertexIndex];
|
||||
if (!positionsBeforeCombination.findPosition(oldPosition.x(), oldPosition.y(), oldPosition.z())) {
|
||||
seamVerticesIndicies[seamVerticesNum++] = vertexIndex + 1;
|
||||
if (!positionsBeforeCombination.map().empty()) {
|
||||
for (size_t vertexIndex = 0; vertexIndex < positionsBeforeSmooth.size(); vertexIndex++) {
|
||||
const auto &oldPosition = positionsBeforeSmooth[vertexIndex];
|
||||
if (!positionsBeforeCombination.findPosition(oldPosition.x(), oldPosition.y(), oldPosition.z())) {
|
||||
seamVerticesIds.push_back(vertexIndex + 1);
|
||||
seamVerticesIndicies.insert(vertexIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool meshChanged = false;
|
||||
if (m_weldEnabled) {
|
||||
if (!seamVerticesIndicies.empty()) {
|
||||
int weldedMeshId = meshWeldSeam(m_meshliteContext, meshIdForSmooth, 0.025, seamVerticesIndicies);
|
||||
{
|
||||
void *testCombinableMesh = convertToCombinableMesh(m_meshliteContext, weldedMeshId);
|
||||
if (nullptr != testCombinableMesh) {
|
||||
deleteCombinableMesh(testCombinableMesh);
|
||||
meshIdForSmooth = weldedMeshId;
|
||||
meshChanged = true;
|
||||
} else {
|
||||
qDebug() << "Weld seam failed, fall back";
|
||||
}
|
||||
}
|
||||
if (seamVerticesNum > 0) {
|
||||
//qDebug() << "smoothSeamFactor:" << smoothSeamFactor << "seamVerticesIndicies.size():" << seamVerticesNum;
|
||||
meshlite_smooth_vertices(m_meshliteContext, meshIdForSmooth, smoothSeamFactor, seamVerticesIndicies, seamVerticesNum);
|
||||
}
|
||||
delete[] seamVerticesIndicies;
|
||||
}
|
||||
}
|
||||
|
||||
if (smoothAll) {
|
||||
meshlite_smooth(m_meshliteContext, meshIdForSmooth, smoothAllFactor);
|
||||
if (smoothSeam) {
|
||||
if (!seamVerticesIds.empty()) {
|
||||
//qDebug() << "smoothSeamFactor:" << smoothSeamFactor << "seamVerticesIndicies.size():" << seamVerticesNum;
|
||||
meshlite_smooth_vertices(m_meshliteContext, meshIdForSmooth, smoothSeamFactor, seamVerticesIds.data(), seamVerticesIds.size());
|
||||
meshChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (smoothAll) {
|
||||
meshlite_smooth(m_meshliteContext, meshIdForSmooth, smoothAllFactor);
|
||||
meshChanged = true;
|
||||
}
|
||||
|
||||
if (meshChanged) {
|
||||
std::vector<QVector3D> positionsAfterSmooth;
|
||||
loadMeshVerticesPositions(m_meshliteContext, meshIdForSmooth, positionsAfterSmooth);
|
||||
Q_ASSERT(positionsBeforeSmooth.size() == positionsAfterSmooth.size());
|
||||
|
@ -543,7 +570,6 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
|||
verticesSources.addPosition(smoothedPosition.x(), smoothedPosition.y(), smoothedPosition.z(), source);
|
||||
}
|
||||
}
|
||||
|
||||
deleteCombinableMesh(resultMesh);
|
||||
resultMesh = convertToCombinableMesh(m_meshliteContext, meshIdForSmooth);
|
||||
}
|
||||
|
@ -655,12 +681,6 @@ void MeshGenerator::process()
|
|||
bmeshNodes.second.begin(), bmeshNodes.second.end());
|
||||
}
|
||||
|
||||
//if (resultMeshId > 0) {
|
||||
// resultMeshId = meshlite_combine_coplanar_faces(m_meshliteContext, resultMeshId);
|
||||
// if (resultMeshId > 0)
|
||||
// resultMeshId = meshlite_fix_hole(m_meshliteContext, resultMeshId);
|
||||
//}
|
||||
|
||||
int triangulatedFinalMeshId = resultMeshId;
|
||||
if (triangulatedFinalMeshId > 0) {
|
||||
std::set<std::pair<PositionMapKey, PositionMapKey>> sharedQuadEdges;
|
||||
|
@ -676,8 +696,6 @@ void MeshGenerator::process()
|
|||
}
|
||||
|
||||
if (resultMeshId > 0) {
|
||||
//int triangulatedFinalMeshId = meshlite_triangulate(m_meshliteContext, resultMeshId);
|
||||
//triangulatedFinalMeshId = resultMeshId;
|
||||
loadGeneratedPositionsToMeshResultContext(m_meshliteContext, triangulatedFinalMeshId);
|
||||
m_mesh = new MeshLoader(m_meshliteContext, resultMeshId, triangulatedFinalMeshId, Theme::white, &m_meshResultContext->triangleColors(), m_smoothNormal);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
void addPartPreviewRequirement(const QUuid &partId);
|
||||
void setGeneratedCacheContext(GeneratedCacheContext *cacheContext);
|
||||
void setSmoothNormal(bool smoothNormal);
|
||||
void setWeldEnabled(bool weldEnabled);
|
||||
MeshLoader *takeResultMesh();
|
||||
MeshLoader *takePartPreviewMesh(const QUuid &partId);
|
||||
const std::set<QUuid> &requirePreviewPartIds();
|
||||
|
@ -57,6 +58,7 @@ private:
|
|||
void *m_meshliteContext;
|
||||
GeneratedCacheContext *m_cacheContext;
|
||||
bool m_smoothNormal;
|
||||
bool m_weldEnabled;
|
||||
float m_mainProfileMiddleX;
|
||||
float m_sideProfileMiddleX;
|
||||
float m_mainProfileMiddleY;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <QDebug>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "meshquadify.h"
|
||||
#include "meshlite.h"
|
||||
|
||||
|
@ -11,12 +12,12 @@ int meshQuadify(void *meshlite, int meshId, const std::set<std::pair<PositionMap
|
|||
int vertexArrayLen = meshlite_get_vertex_position_array(meshlite, meshId, vertexPositions, vertexCount * 3);
|
||||
int offset = 0;
|
||||
Q_ASSERT(vertexArrayLen == vertexCount * 3);
|
||||
std::map<int, PositionMapKey> positionKeyMap;
|
||||
std::vector<PositionMapKey> positionKeyMap;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float x = vertexPositions[offset + 0];
|
||||
float y = vertexPositions[offset + 1];
|
||||
float z = vertexPositions[offset + 2];
|
||||
positionKeyMap[i] = positionMapForMakeKey->makeKey(x, y, z);
|
||||
positionKeyMap.push_back(positionMapForMakeKey->makeKey(x, y, z));
|
||||
offset += 3;
|
||||
}
|
||||
int faceCount = meshlite_get_face_count(meshlite, meshId);
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <QVector3D>
|
||||
#include <unordered_map>
|
||||
#include "meshweldseam.h"
|
||||
#include "meshutil.h"
|
||||
|
||||
int meshWeldSeam(void *meshlite, int meshId, float allowedSmallestDistance, const std::unordered_set<int> &seamVerticesIndicies)
|
||||
{
|
||||
int vertexCount = meshlite_get_vertex_count(meshlite, meshId);
|
||||
float *vertexPositions = new float[vertexCount * 3];
|
||||
int vertexArrayLen = meshlite_get_vertex_position_array(meshlite, meshId, vertexPositions, vertexCount * 3);
|
||||
int offset = 0;
|
||||
Q_ASSERT(vertexArrayLen == vertexCount * 3);
|
||||
std::vector<QVector3D> positions;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float x = vertexPositions[offset + 0];
|
||||
float y = vertexPositions[offset + 1];
|
||||
float z = vertexPositions[offset + 2];
|
||||
positions.push_back(QVector3D(x, y, z));
|
||||
offset += 3;
|
||||
}
|
||||
int faceCount = meshlite_get_face_count(meshlite, meshId);
|
||||
int *faceVertexNumAndIndices = new int[faceCount * MAX_VERTICES_PER_FACE];
|
||||
int filledLength = meshlite_get_face_index_array(meshlite, meshId, faceVertexNumAndIndices, faceCount * MAX_VERTICES_PER_FACE);
|
||||
int i = 0;
|
||||
std::vector<std::vector<int>> newFaceIndicies;
|
||||
while (i < filledLength) {
|
||||
int num = faceVertexNumAndIndices[i++];
|
||||
Q_ASSERT(num > 0 && num <= MAX_VERTICES_PER_FACE);
|
||||
if (num < 3) {
|
||||
i += num;
|
||||
continue;
|
||||
}
|
||||
std::vector<int> indices;
|
||||
for (int j = 0; j < num; j++) {
|
||||
int index = faceVertexNumAndIndices[i++];
|
||||
Q_ASSERT(index >= 0 && index < vertexCount);
|
||||
indices.push_back(index);
|
||||
}
|
||||
newFaceIndicies.push_back(indices);
|
||||
}
|
||||
float squareOfAllowedSmallestDistance = allowedSmallestDistance * allowedSmallestDistance;
|
||||
int weldedMesh = 0;
|
||||
std::map<int, int> weldVertexToMap;
|
||||
std::unordered_set<int> weldTargetVertices;
|
||||
std::unordered_set<int> processedFaces;
|
||||
std::map<std::pair<int, int>, std::pair<int, int>> triangleEdgeMap;
|
||||
std::unordered_map<int, int> vertexAdjFaceCountMap;
|
||||
for (int i = 0; i < (int)newFaceIndicies.size(); i++) {
|
||||
const auto &faceIndicies = newFaceIndicies[i];
|
||||
if (faceIndicies.size() == 3) {
|
||||
vertexAdjFaceCountMap[faceIndicies[0]]++;
|
||||
vertexAdjFaceCountMap[faceIndicies[1]]++;
|
||||
vertexAdjFaceCountMap[faceIndicies[2]]++;
|
||||
triangleEdgeMap[std::make_pair(faceIndicies[0], faceIndicies[1])] = std::make_pair(i, faceIndicies[2]);
|
||||
triangleEdgeMap[std::make_pair(faceIndicies[1], faceIndicies[2])] = std::make_pair(i, faceIndicies[0]);
|
||||
triangleEdgeMap[std::make_pair(faceIndicies[2], faceIndicies[0])] = std::make_pair(i, faceIndicies[1]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < (int)newFaceIndicies.size(); i++) {
|
||||
if (processedFaces.find(i) != processedFaces.end())
|
||||
continue;
|
||||
const auto &faceIndicies = newFaceIndicies[i];
|
||||
if (faceIndicies.size() == 3) {
|
||||
bool indiciesSeamCheck[3] = {
|
||||
seamVerticesIndicies.empty() || seamVerticesIndicies.find(faceIndicies[0]) != seamVerticesIndicies.end(),
|
||||
seamVerticesIndicies.empty() || seamVerticesIndicies.find(faceIndicies[1]) != seamVerticesIndicies.end(),
|
||||
seamVerticesIndicies.empty() || seamVerticesIndicies.find(faceIndicies[2]) != seamVerticesIndicies.end()
|
||||
};
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int next = (j + 1) % 3;
|
||||
int nextNext = (j + 2) % 3;
|
||||
if (indiciesSeamCheck[j] && indiciesSeamCheck[next]) {
|
||||
std::pair<int, int> edge = std::make_pair(faceIndicies[j], faceIndicies[next]);
|
||||
int thirdVertexIndex = faceIndicies[nextNext];
|
||||
if ((positions[edge.first] - positions[edge.second]).lengthSquared() < squareOfAllowedSmallestDistance) {
|
||||
auto oppositeEdge = std::make_pair(edge.second, edge.first);
|
||||
auto findOppositeFace = triangleEdgeMap.find(oppositeEdge);
|
||||
if (findOppositeFace == triangleEdgeMap.end()) {
|
||||
qDebug() << "Find opposite edge failed";
|
||||
continue;
|
||||
}
|
||||
int oppositeFaceIndex = findOppositeFace->second.first;
|
||||
// Weld on the longer edge vertex
|
||||
if (((positions[edge.first] - positions[thirdVertexIndex]).lengthSquared() <
|
||||
(positions[edge.second] - positions[thirdVertexIndex]).lengthSquared()) &&
|
||||
vertexAdjFaceCountMap[edge.second] <= 4 &&
|
||||
weldVertexToMap.find(edge.second) == weldVertexToMap.end()) {
|
||||
weldVertexToMap[edge.second] = edge.first;
|
||||
weldTargetVertices.insert(edge.first);
|
||||
processedFaces.insert(i);
|
||||
processedFaces.insert(oppositeFaceIndex);
|
||||
break;
|
||||
} else if (vertexAdjFaceCountMap[edge.first] <= 4 &&
|
||||
weldVertexToMap.find(edge.first) == weldVertexToMap.end()) {
|
||||
weldVertexToMap[edge.first] = edge.second;
|
||||
weldTargetVertices.insert(edge.second);
|
||||
processedFaces.insert(i);
|
||||
processedFaces.insert(oppositeFaceIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<int> newFaceVertexNumAndIndices;
|
||||
int weldedCount = 0;
|
||||
int faceCountAfterWeld = 0;
|
||||
for (int i = 0; i < (int)newFaceIndicies.size(); i++) {
|
||||
const auto &faceIndicies = newFaceIndicies[i];
|
||||
std::vector<int> mappedFaceIndicies;
|
||||
bool errored = false;
|
||||
for (const auto &index: faceIndicies) {
|
||||
int finalIndex = index;
|
||||
int mapTimes = 0;
|
||||
while (mapTimes < 500) {
|
||||
auto findMapResult = weldVertexToMap.find(finalIndex);
|
||||
if (findMapResult == weldVertexToMap.end())
|
||||
break;
|
||||
finalIndex = findMapResult->second;
|
||||
mapTimes++;
|
||||
}
|
||||
if (mapTimes >= 500) {
|
||||
qDebug() << "Map too much times";
|
||||
errored = true;
|
||||
break;
|
||||
}
|
||||
mappedFaceIndicies.push_back(finalIndex);
|
||||
}
|
||||
if (errored || mappedFaceIndicies.size() < 3)
|
||||
continue;
|
||||
bool welded = false;
|
||||
for (decltype(mappedFaceIndicies.size()) j = 0; j < mappedFaceIndicies.size(); j++) {
|
||||
int next = (j + 1) % 3;
|
||||
if (mappedFaceIndicies[j] == mappedFaceIndicies[next]) {
|
||||
welded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (welded) {
|
||||
weldedCount++;
|
||||
continue;
|
||||
}
|
||||
faceCountAfterWeld++;
|
||||
newFaceVertexNumAndIndices.push_back(mappedFaceIndicies.size());
|
||||
for (const auto &index: mappedFaceIndicies) {
|
||||
newFaceVertexNumAndIndices.push_back(index);
|
||||
}
|
||||
}
|
||||
qDebug() << "Welded" << weldedCount << "triangles(" << newFaceIndicies.size() << " - " << weldedCount << " = " << faceCountAfterWeld << ")";
|
||||
weldedMesh = meshlite_build(meshlite, vertexPositions, vertexCount, newFaceVertexNumAndIndices.data(), newFaceVertexNumAndIndices.size());
|
||||
delete[] faceVertexNumAndIndices;
|
||||
delete[] vertexPositions;
|
||||
return weldedMesh;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef MESH_WELD_SEAM_H
|
||||
#define MESH_WELD_SEAM_H
|
||||
#include "meshlite.h"
|
||||
#include <unordered_set>
|
||||
|
||||
int meshWeldSeam(void *meshlite, int meshId, float allowedSmallestDistance,
|
||||
const std::unordered_set<int> &seamVerticesIndicies=std::unordered_set<int>());
|
||||
|
||||
#endif
|
|
@ -28,6 +28,7 @@ SkeletonDocument::SkeletonDocument() :
|
|||
textureAmbientOcclusionImage(nullptr),
|
||||
textureColorImage(nullptr),
|
||||
rigType(RigType::None),
|
||||
weldEnabled(false),
|
||||
// private
|
||||
m_isResultMeshObsolete(false),
|
||||
m_meshGenerator(nullptr),
|
||||
|
@ -1213,6 +1214,12 @@ void SkeletonDocument::toggleSmoothNormal()
|
|||
regenerateMesh();
|
||||
}
|
||||
|
||||
void SkeletonDocument::enableWeld(bool enabled)
|
||||
{
|
||||
weldEnabled = enabled;
|
||||
regenerateMesh();
|
||||
}
|
||||
|
||||
void SkeletonDocument::generateMesh()
|
||||
{
|
||||
if (nullptr != m_meshGenerator || m_batchChangeRefCount > 0) {
|
||||
|
@ -1233,6 +1240,7 @@ void SkeletonDocument::generateMesh()
|
|||
resetDirtyFlags();
|
||||
m_meshGenerator = new MeshGenerator(snapshot, thread);
|
||||
m_meshGenerator->setSmoothNormal(m_smoothNormal);
|
||||
m_meshGenerator->setWeldEnabled(weldEnabled);
|
||||
m_meshGenerator->setGeneratedCacheContext(&m_generatedCacheContext);
|
||||
if (nullptr != m_sharedContextWidget)
|
||||
m_meshGenerator->setSharedContextWidget(m_sharedContextWidget);
|
||||
|
|
|
@ -465,6 +465,7 @@ public: // need initialize
|
|||
QImage *textureAmbientOcclusionImage;
|
||||
QImage *textureColorImage;
|
||||
RigType rigType;
|
||||
bool weldEnabled;
|
||||
public:
|
||||
SkeletonDocument();
|
||||
~SkeletonDocument();
|
||||
|
@ -594,6 +595,7 @@ public slots:
|
|||
void enableAllPositionRelatedLocks();
|
||||
void disableAllPositionRelatedLocks();
|
||||
void toggleSmoothNormal();
|
||||
void enableWeld(bool enabled);
|
||||
void setRigType(RigType toRigType);
|
||||
void addPose(QString name, std::map<QString, std::map<QString, QString>> parameters);
|
||||
void removePose(QUuid poseId);
|
||||
|
|
|
@ -97,7 +97,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
|||
m_document(nullptr),
|
||||
m_firstShow(true),
|
||||
m_documentSaved(true),
|
||||
m_exportPreviewWidget(nullptr)
|
||||
m_exportPreviewWidget(nullptr),
|
||||
m_advanceSettingWidget(nullptr)
|
||||
{
|
||||
if (!g_logBrowser) {
|
||||
g_logBrowser = new LogBrowser;
|
||||
|
@ -544,6 +545,12 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
|||
connect(m_showDebugDialogAction, &QAction::triggered, g_logBrowser, &LogBrowser::showDialog);
|
||||
m_windowMenu->addAction(m_showDebugDialogAction);
|
||||
|
||||
m_showAdvanceSettingAction = new QAction(tr("Advance"), this);
|
||||
connect(m_showAdvanceSettingAction, &QAction::triggered, this, &SkeletonDocumentWindow::showAdvanceSetting);
|
||||
#ifndef NDEBUG
|
||||
m_windowMenu->addAction(m_showAdvanceSettingAction);
|
||||
#endif
|
||||
|
||||
m_helpMenu = menuBar()->addMenu(tr("Help"));
|
||||
|
||||
m_viewSourceAction = new QAction(tr("Fork me on GitHub"), this);
|
||||
|
@ -1061,6 +1068,15 @@ void SkeletonDocumentWindow::open()
|
|||
setCurrentFilename(filename);
|
||||
}
|
||||
|
||||
void SkeletonDocumentWindow::showAdvanceSetting()
|
||||
{
|
||||
if (nullptr == m_advanceSettingWidget) {
|
||||
m_advanceSettingWidget = new AdvanceSettingWidget(m_document, this);
|
||||
}
|
||||
m_advanceSettingWidget->show();
|
||||
m_advanceSettingWidget->raise();
|
||||
}
|
||||
|
||||
void SkeletonDocumentWindow::exportObjResult()
|
||||
{
|
||||
QString filename = QFileDialog::getSaveFileName(this, QString(), QString(),
|
||||
|
@ -1097,10 +1113,8 @@ void SkeletonDocumentWindow::showExportPreview()
|
|||
connect(m_document, &SkeletonDocument::resultBakedTextureChanged, m_exportPreviewWidget, &ExportPreviewWidget::updateTexturePreview);
|
||||
registerDialog(m_exportPreviewWidget);
|
||||
}
|
||||
if (m_document->isPostProcessResultObsolete()) {
|
||||
m_document->postProcess();
|
||||
}
|
||||
m_exportPreviewWidget->show();
|
||||
m_exportPreviewWidget->raise();
|
||||
}
|
||||
|
||||
void SkeletonDocumentWindow::exportGltfResult()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "rigwidget.h"
|
||||
#include "skeletonbonemark.h"
|
||||
#include "posemanagewidget.h"
|
||||
#include "advancesettingwidget.h"
|
||||
|
||||
class SkeletonGraphicsWidget;
|
||||
|
||||
|
@ -59,6 +60,7 @@ public slots:
|
|||
void updateRigWeightRenderWidget();
|
||||
void registerDialog(QWidget *widget);
|
||||
void unregisterDialog(QWidget *widget);
|
||||
void showAdvanceSetting();
|
||||
private:
|
||||
void initLockButton(QPushButton *button);
|
||||
void setCurrentFilename(const QString &filename);
|
||||
|
@ -68,6 +70,7 @@ private:
|
|||
bool m_firstShow;
|
||||
bool m_documentSaved;
|
||||
ExportPreviewWidget *m_exportPreviewWidget;
|
||||
AdvanceSettingWidget *m_advanceSettingWidget;
|
||||
std::vector<QWidget *> m_dialogs;
|
||||
private:
|
||||
QString m_currentFilename;
|
||||
|
@ -75,7 +78,6 @@ private:
|
|||
ModelWidget *m_modelRenderWidget;
|
||||
SkeletonGraphicsWidget *m_graphicsWidget;
|
||||
RigWidget *m_rigWidget;
|
||||
PoseManageWidget *m_poseManageWidget;
|
||||
|
||||
QMenu *m_fileMenu;
|
||||
QAction *m_newWindowAction;
|
||||
|
@ -135,6 +137,7 @@ private:
|
|||
QAction *m_showDebugDialogAction;
|
||||
QAction *m_showRigAction;
|
||||
QAction *m_showPosesAction;
|
||||
QAction *m_showAdvanceSettingAction;
|
||||
|
||||
QMenu *m_helpMenu;
|
||||
QAction *m_viewSourceAction;
|
||||
|
|
Loading…
Reference in New Issue