3D PDF: Mesh

This commit is contained in:
Jakub Melka
2022-11-18 19:28:27 +01:00
parent 19f04aa975
commit caed76640c
2 changed files with 377 additions and 3 deletions

View File

@@ -847,7 +847,7 @@ public:
};
const QString& getName() const { return m_pointSetName; }
const std::vector<UpdateItem>& getUpdateItems() const;
const std::vector<UpdateItem>& getUpdateItems() const { return m_updateItems; }
private:
QString m_pointSetName;
@@ -1490,6 +1490,14 @@ public:
void processLineSet(const PDF3D_U3D_Decoder& decoder);
void processTexture(const PDF3D_U3D_Decoder& decoder);
void addBaseMeshGeometry(PDF3D_U3D_MeshGeometry* geometry,
const PDF3D_U3D_CLODMeshDeclarationBlock* declarationBlock,
const PDF3D_U3D_CLODBaseMeshContinuationBlock* geometryBlock);
void addPointSetGeometry(PDF3D_U3D_PointSetGeometry* geometry,
const PDF3D_U3D_PointSetDeclarationBlock* declarationBlock,
const PDF3D_U3D_PointSetContinuationBlock* geometryBlock);
void addLineSetGeometry(PDF3D_U3D_LineSetGeometry* geometry,
const PDF3D_U3D_LineSetDeclarationBlock* declarationBlock,
const PDF3D_U3D_LineSetContinuationBlock* geometryBlock);
@@ -2342,6 +2350,8 @@ void PDF3D_U3D_Parser::processCLODMesh(const PDF3D_U3D_Decoder& decoder)
auto block = parseBlock(decoder.front());
const PDF3D_U3D_CLODMeshDeclarationBlock* declarationBlock = dynamic_cast<const PDF3D_U3D_CLODMeshDeclarationBlock*>(block.data());
QSharedPointer<PDF3D_U3D_MeshGeometry> geometry(new PDF3D_U3D_MeshGeometry());
for (auto it = std::next(decoder.begin()); it != decoder.end(); ++it)
{
auto blockData = *it;
@@ -2349,8 +2359,10 @@ void PDF3D_U3D_Parser::processCLODMesh(const PDF3D_U3D_Decoder& decoder)
{
case PDF3D_U3D_Block_Info::BT_GeneratorCLODBaseMesh:
{
// TODO: process block data
auto currentBlock = PDF3D_U3D_CLODBaseMeshContinuationBlock::parse(blockData.blockData, blockData.metaData, this, declarationBlock);
const PDF3D_U3D_CLODBaseMeshContinuationBlock* typedBlock = dynamic_cast<const PDF3D_U3D_CLODBaseMeshContinuationBlock*>(currentBlock.data());
addBaseMeshGeometry(geometry.data(), declarationBlock, typedBlock);
break;
}
@@ -2363,8 +2375,14 @@ void PDF3D_U3D_Parser::processCLODMesh(const PDF3D_U3D_Decoder& decoder)
default:
m_errors << PDFTranslationContext::tr("Invalid block type '%1' for CLOD mesh!").arg(blockData.blockType, 8, 16);
break;
}
}
if (!geometry->isEmpty())
{
m_object.setGeometry(declarationBlock->getName(), std::move(geometry));
}
}
void PDF3D_U3D_Parser::processPointSet(const PDF3D_U3D_Decoder& decoder)
@@ -2372,6 +2390,8 @@ void PDF3D_U3D_Parser::processPointSet(const PDF3D_U3D_Decoder& decoder)
auto block = parseBlock(decoder.front());
const PDF3D_U3D_PointSetDeclarationBlock* declarationBlock = dynamic_cast<const PDF3D_U3D_PointSetDeclarationBlock*>(block.data());
QSharedPointer<PDF3D_U3D_PointSetGeometry> geometry(new PDF3D_U3D_PointSetGeometry());
for (auto it = std::next(decoder.begin()); it != decoder.end(); ++it)
{
auto blockData = *it;
@@ -2379,15 +2399,23 @@ void PDF3D_U3D_Parser::processPointSet(const PDF3D_U3D_Decoder& decoder)
{
case PDF3D_U3D_Block_Info::BT_GeneratorPointSetCont:
{
// TODO: process block data
auto currentBlock = PDF3D_U3D_PointSetContinuationBlock::parse(blockData.blockData, blockData.metaData, this, declarationBlock);
const PDF3D_U3D_PointSetContinuationBlock* typedBlock = dynamic_cast<const PDF3D_U3D_PointSetContinuationBlock*>(currentBlock.data());
addPointSetGeometry(geometry.data(), declarationBlock, typedBlock);
break;
}
default:
m_errors << PDFTranslationContext::tr("Invalid block type '%1' for Point set!").arg(blockData.blockType, 8, 16);
break;
}
}
if (!geometry->isEmpty())
{
m_object.setGeometry(declarationBlock->getName(), std::move(geometry));
}
}
void PDF3D_U3D_Parser::processLineSet(const PDF3D_U3D_Decoder& decoder)
@@ -2413,6 +2441,7 @@ void PDF3D_U3D_Parser::processLineSet(const PDF3D_U3D_Decoder& decoder)
default:
m_errors << PDFTranslationContext::tr("Invalid block type '%1' for line set!").arg(blockData.blockType, 8, 16);
break;
}
}
@@ -2550,6 +2579,217 @@ void PDF3D_U3D_Parser::processTexture(const PDF3D_U3D_Decoder& decoder)
m_object.setTextureResource(declarationBlock->getResourceName(), std::move(texture));
}
void PDF3D_U3D_Parser::addBaseMeshGeometry(PDF3D_U3D_MeshGeometry* geometry,
const PDF3D_U3D_CLODMeshDeclarationBlock* declarationBlock,
const PDF3D_U3D_CLODBaseMeshContinuationBlock* geometryBlock)
{
const std::vector<PDF3D_U3D_Vec3>& basePositions = geometryBlock->getBasePositions();
const std::vector<PDF3D_U3D_Vec3>& baseNormals = geometryBlock->getBaseNormals();
const std::vector<PDF3D_U3D_Vec4>& baseDiffuseColors = geometryBlock->getBaseDiffuseColors();
const std::vector<PDF3D_U3D_Vec4>& baseSpecularColors = geometryBlock->getBaseSpecularColors();
const std::vector<PDF3D_U3D_Vec4>& baseTextureCoords = geometryBlock->getBaseTextureCoords();
const std::vector<PDF3D_U3D_CLODBaseMeshContinuationBlock::BaseFace>& baseFaces = geometryBlock->getBaseFaces();
for (const PDF3D_U3D_Vec3& value : basePositions)
{
geometry->addPosition(QVector3D(value[0], value[1], value[2]));
}
for (const PDF3D_U3D_Vec3& value : baseNormals)
{
geometry->addNormal(QVector3D(value[0], value[1], value[2]));
}
for (const PDF3D_U3D_Vec4& value : baseDiffuseColors)
{
geometry->addDiffuseColor(QVector4D(value[0], value[1], value[2], value[3]));
}
for (const PDF3D_U3D_Vec4& value : baseSpecularColors)
{
geometry->addSpecularColor(QVector4D(value[0], value[1], value[2], value[3]));
}
for (const PDF3D_U3D_Vec4& value : baseTextureCoords)
{
geometry->addTextureCoordinate(QVector4D(value[0], value[1], value[2], value[3]));
}
size_t maxTextureLayers = 0;
for (const PDF3D_U3D_CLODBaseMeshContinuationBlock::BaseFace& face : baseFaces)
{
PDF3D_U3D_MeshGeometry::Triangle triangle;
const PDF3D_U3D_ShadingDescription* shading = declarationBlock->getShadingDescriptionItem(face.m_shadingId);
if (shading)
{
triangle.hasDiffuse = shading->hasDiffuseColors();
triangle.hasSpecular = shading->hasSpecularColors();
triangle.hasTexture = shading->hasTextures();
}
Q_ASSERT(triangle.vertices.size() == face.m_corners.size());
for (size_t i = 0; i < triangle.vertices.size(); ++i)
{
PDF3D_U3D_MeshGeometry::Vertex& vertex = triangle.vertices[i];
const PDF3D_U3D_CLODBaseMeshContinuationBlock::BaseCornerInfo& vertexInfo = face.m_corners[i];
vertex.positionIndex = vertexInfo.basePositionIndex;
vertex.normalIndex = vertexInfo.baseNormalIndex;
vertex.diffuseColorIndex = vertexInfo.baseDiffuseColorIndex;
vertex.specularColorIndex = vertexInfo.baseSpecularColorIndex;
vertex.textureCoordIndex = !vertexInfo.baseTextureCoordIndex.empty() ? vertexInfo.baseTextureCoordIndex.front() : 0;
maxTextureLayers = qMax(maxTextureLayers, vertexInfo.baseTextureCoordIndex.size());
}
geometry->addTriangle(std::move(triangle));
}
if (maxTextureLayers > 1)
{
m_errors << PDFTranslationContext::tr("More than one texture not supported.");
}
}
void PDF3D_U3D_Parser::addPointSetGeometry(PDF3D_U3D_PointSetGeometry* geometry,
const PDF3D_U3D_PointSetDeclarationBlock* declarationBlock,
const PDF3D_U3D_PointSetContinuationBlock* geometryBlock)
{
const auto& updateItems = geometryBlock->getUpdateItems();
if (geometry->isEmpty())
{
geometry->addNormal(QVector3D());
geometry->addDiffuseColor(QVector4D());
geometry->addSpecularColor(QVector4D());
}
bool hasTextures = false;
for (const PDF3D_U3D_PointSetContinuationBlock::UpdateItem& item : updateItems)
{
// 1. Determine position
const size_t splitPositionIndex = item.splitPositionIndex;
QVector3D splitPosition = geometry->getPosition(splitPositionIndex);
QVector3D currentPosition = getDequantizedVec3(item.newPositionInfo, splitPosition, declarationBlock->getPositionInverseQuant());
geometry->addPosition(currentPosition);
auto points = geometry->queryPointsByVertexIndex(splitPositionIndex);
size_t predictedNormalCount = 0;
size_t predictedDiffuseCount = 0;
size_t predictedSpecularCount = 0;
QVector3D predictedNormal(0, 0, 0);
QVector4D predictedDiffuseColor(0, 0, 0, 0);
QVector4D predictedSpecularColor(0, 0, 0, 0);
// 2. Prepare predicted values
for (const PDF3D_U3D_PointSetGeometry::Point & point : points)
{
auto description = declarationBlock->getShadingDescriptionItem(point.shadingId);
const bool hasDiffuse = description && description->hasDiffuseColors();
const bool hasSpecular = description && description->hasSpecularColors();
if (point.position == splitPositionIndex)
{
predictedNormal += geometry->getNormal(point.normal);
++predictedNormalCount;
if (hasDiffuse)
{
predictedDiffuseColor += geometry->getDiffuseColor(point.diffuseColor);
++predictedDiffuseCount;
}
if (hasSpecular)
{
predictedSpecularColor += geometry->getSpecularColor(point.specularColor);
++predictedSpecularCount;
}
}
}
if (predictedNormalCount > 0)
{
predictedNormal /= qreal(predictedNormalCount);
}
if (predictedDiffuseCount > 0)
{
predictedDiffuseColor /= qreal(predictedDiffuseCount);
}
if (predictedSpecularCount > 0)
{
predictedSpecularColor /= qreal(predictedSpecularCount);
}
const size_t normalCount = geometry->getNormalCount();
for (const auto& normal : item.newNormals)
{
QVector3D normalVector = getDequantizedVec3(normal, predictedNormal, declarationBlock->getNormalInverseQuant());
geometry->addNormal(normalVector);
}
for (const PDF3D_U3D_PointSetContinuationBlock::NewPointInfo& point : item.newPoints)
{
PDF3D_U3D_PointSetGeometry::Point processedPoint;
processedPoint.shadingId = static_cast<uint32_t>(point.shadingId);
processedPoint.position = static_cast<uint32_t>(geometry->getPositionCount() - 1);
processedPoint.normal = static_cast<uint32_t>(point.normalLocalIndex + normalCount);
if (auto description = declarationBlock->getShadingDescriptionItem(point.shadingId))
{
if (description->hasDiffuseColors())
{
if (point.duplicateDiffuse)
{
processedPoint.diffuseColor = static_cast<uint32_t>(geometry->getDiffuseColorCount() - 1);
}
else
{
processedPoint.diffuseColor = static_cast<uint32_t>(geometry->getDiffuseColorCount());
QVector4D diffuseColor = getDequantizedVec4(point.diffuseColor, predictedDiffuseColor, declarationBlock->getDiffuseColorInverseQuant());
geometry->addDiffuseColor(diffuseColor);
}
}
if (description->hasSpecularColors())
{
if (point.duplicateSpecular)
{
processedPoint.specularColor = static_cast<uint32_t>(geometry->getSpecularColorCount() - 1);
}
else
{
processedPoint.specularColor = static_cast<uint32_t>(geometry->getSpecularColorCount());
QVector4D specularColor = getDequantizedVec4(point.specularColor, predictedSpecularColor, declarationBlock->getSpecularColorInverseQuant());
geometry->addSpecularColor(specularColor);
}
}
if (description->hasTextures())
{
hasTextures = true;
}
}
geometry->addPoint(std::move(processedPoint));
}
}
if (hasTextures)
{
m_errors << PDFTranslationContext::tr("Textures for points are not supported.");
}
}
void PDF3D_U3D_Parser::addLineSetGeometry(PDF3D_U3D_LineSetGeometry* geometry,
const PDF3D_U3D_LineSetDeclarationBlock* declarationBlock,
const PDF3D_U3D_LineSetContinuationBlock* geometryBlock)
@@ -6224,6 +6464,32 @@ std::vector<PDF3D_U3D_LineSetGeometry::Line> PDF3D_U3D_LineSetGeometry::queryLin
return result;
}
void PDF3D_U3D_PointSetGeometry::addPoint(Point point)
{
const size_t pointIndex = m_points.size();
m_points.emplace_back(std::move(point));
m_mapPosIndexToPoint.insert(std::make_pair(m_points.back().position, pointIndex));
}
std::vector<PDF3D_U3D_PointSetGeometry::Point> PDF3D_U3D_PointSetGeometry::queryPointsByVertexIndex(size_t vertexIndex) const
{
std::vector<PDF3D_U3D_PointSetGeometry::Point> result;
auto iterators = m_mapPosIndexToPoint.equal_range(vertexIndex);
result.reserve(std::distance(iterators.first, iterators.second));
for (auto it = iterators.first; it != iterators.second; ++it)
{
result.push_back(m_points[it->second]);
}
return result;
}
void PDF3D_U3D_MeshGeometry::addTriangle(Triangle triangle)
{
m_triangles.emplace_back(std::move(triangle));
}
} // namespace u3d
} // namespace pdf

View File

@@ -90,7 +90,9 @@ private:
bool m_isBackVisible = true;
};
class PDF3D_U3D_MeshGeometry;
class PDF3D_U3D_LineSetGeometry;
class PDF3D_U3D_PointSetGeometry;
class PDF4QTLIBSHARED_EXPORT PDF3D_U3D_Geometry
{
@@ -98,10 +100,116 @@ public:
PDF3D_U3D_Geometry() = default;
virtual ~PDF3D_U3D_Geometry() = default;
virtual PDF3D_U3D_MeshGeometry* asMeshGeometry() { return nullptr; }
virtual const PDF3D_U3D_MeshGeometry* asMeshGeometry() const { return nullptr; }
virtual PDF3D_U3D_PointSetGeometry* asPointSetGeometry() { return nullptr; }
virtual const PDF3D_U3D_PointSetGeometry* asPointSetGeometry() const { return nullptr; }
virtual PDF3D_U3D_LineSetGeometry* asLineSetGeometry() { return nullptr; }
virtual const PDF3D_U3D_LineSetGeometry* asLineSetGeometry() const { return nullptr; }
};
class PDF4QTLIBSHARED_EXPORT PDF3D_U3D_MeshGeometry : public PDF3D_U3D_Geometry
{
public:
virtual PDF3D_U3D_MeshGeometry* asMeshGeometry() override { return this; }
virtual const PDF3D_U3D_MeshGeometry* asMeshGeometry() const override { return this; }
struct Vertex
{
uint32_t positionIndex = 0;
uint32_t normalIndex = 0;
uint32_t diffuseColorIndex = 0;
uint32_t specularColorIndex = 0;
uint32_t textureCoordIndex = 0;
};
struct Triangle
{
bool hasDiffuse = false;
bool hasSpecular = false;
bool hasTexture = false;
std::array<Vertex, 3> vertices;
};
bool isEmpty() const { return m_triangles.empty(); }
QVector3D getPosition(size_t index) const { return index < m_positions.size() ? m_positions[index] : QVector3D(0, 0, 0); }
QVector3D getNormal(size_t index) const { return index < m_normals.size() ? m_normals[index] : QVector3D(0, 0, 0); }
QVector4D getDiffuseColor(size_t index) const { return index < m_diffuseColors.size() ? m_diffuseColors[index] : QVector4D(0, 0, 0, 0); }
QVector4D getSpecularColor(size_t index) const { return index < m_specularColors.size() ? m_specularColors[index] : QVector4D(0, 0, 0, 0); }
QVector4D getTextureCoordinate(size_t index) const { return index < m_textureCoordinates.size() ? m_textureCoordinates[index] : QVector4D(0, 0, 0, 0); }
void addPosition(const QVector3D& position) { m_positions.emplace_back(position); }
void addNormal(const QVector3D& normal) { m_normals.emplace_back(normal); }
void addDiffuseColor(const QVector4D& color) { m_diffuseColors.emplace_back(color); }
void addSpecularColor(const QVector4D& color) { m_specularColors.emplace_back(color); }
void addTextureCoordinate(const QVector4D& coordinate) { m_textureCoordinates.emplace_back(coordinate); }
void addTriangle(Triangle triangle);
size_t getPositionCount() const { return m_positions.size(); }
size_t getNormalCount() const { return m_normals.size(); }
size_t getDiffuseColorCount() const { return m_diffuseColors.size(); }
size_t getSpecularColorCount() const { return m_specularColors.size(); }
size_t getTextureCoordinateCount() const { return m_textureCoordinates.size(); }
private:
std::vector<QVector3D> m_positions;
std::vector<QVector3D> m_normals;
std::vector<QVector4D> m_diffuseColors;
std::vector<QVector4D> m_specularColors;
std::vector<QVector4D> m_textureCoordinates;
std::vector<Triangle> m_triangles;
std::unordered_multimap<size_t, size_t> m_mapPosIndexToTriangle;
};
class PDF4QTLIBSHARED_EXPORT PDF3D_U3D_PointSetGeometry : public PDF3D_U3D_Geometry
{
public:
virtual PDF3D_U3D_PointSetGeometry* asPointSetGeometry() override { return this; }
virtual const PDF3D_U3D_PointSetGeometry* asPointSetGeometry() const override { return this; }
struct Point
{
uint32_t shadingId = 0;
uint32_t position = 0;
uint32_t normal = 0;
uint32_t diffuseColor = 0;
uint32_t specularColor = 0;
};
bool isEmpty() const { return m_positions.empty(); }
QVector3D getPosition(size_t index) const { return index < m_positions.size() ? m_positions[index] : QVector3D(0, 0, 0); }
QVector3D getNormal(size_t index) const { return index < m_normals.size() ? m_normals[index] : QVector3D(0, 0, 0); }
QVector4D getDiffuseColor(size_t index) const { return index < m_diffuseColors.size() ? m_diffuseColors[index] : QVector4D(0, 0, 0, 0); }
QVector4D getSpecularColor(size_t index) const { return index < m_specularColors.size() ? m_specularColors[index] : QVector4D(0, 0, 0, 0); }
void addPosition(const QVector3D& position) { m_positions.emplace_back(position); }
void addNormal(const QVector3D& normal) { m_normals.emplace_back(normal); }
void addDiffuseColor(const QVector4D& color) { m_diffuseColors.emplace_back(color); }
void addSpecularColor(const QVector4D& color) { m_specularColors.emplace_back(color); }
void addPoint(Point point);
/// Returns all points containing given vertex index
std::vector<Point> queryPointsByVertexIndex(size_t vertexIndex) const;
size_t getPositionCount() const { return m_positions.size(); }
size_t getNormalCount() const { return m_normals.size(); }
size_t getDiffuseColorCount() const { return m_diffuseColors.size(); }
size_t getSpecularColorCount() const { return m_specularColors.size(); }
private:
std::vector<QVector3D> m_positions;
std::vector<QVector3D> m_normals;
std::vector<QVector4D> m_diffuseColors;
std::vector<QVector4D> m_specularColors;
std::vector<Point> m_points;
std::unordered_multimap<size_t, size_t> m_mapPosIndexToPoint;
};
class PDF4QTLIBSHARED_EXPORT PDF3D_U3D_LineSetGeometry : public PDF3D_U3D_Geometry
{
public: