我用dual marching cubes algorithm提取了一个等值面。
从算法中,我得到了以下数据:
# cube.obj wavefront file
## shared vertices (cartesian coordinates)
v 1.0 1.0 0.0
v 0.0 1.0 0.0
v 0.0 0.0 0.0
v 1.0 0.0 0.0
v 1.0 0.0 1.0
v 0.0 0.0 1.0
v 0.0 1.0 1.0
v 1.0 1.0 1.0
## faces (vertex indices are forming quad patches)
f 1 4 3 2
f 5 6 3 4
f 7 2 3 6
f 8 5 4 1
f 8 1 2 7
f 8 7 6 5
(绘制三角表面的说明here)。
主要问题:是否可以使用Qt3d从此四边形面数据渲染等值面?
奖金问题:如何使表面透明或将其绘制为线框?
这是我走了多远:
#include <QApplication>
#include <QWidget>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DRender/QCamera>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DRender/QAttribute>
#include <Qt3DRender/QBuffer>
#include <Qt3DExtras/QPhongAlphaMaterial>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// Root entity
auto *rootEntity = new Qt3DCore::QEntity();
// Window container
auto qt3DWindow = new Qt3DExtras::Qt3DWindow();
qt3DWindow->setRootEntity(rootEntity);
auto widget = QWidget::createWindowContainer(qt3DWindow);
// Camera
auto *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
qt3DWindow->setRootEntity(rootEntity);
qt3DWindow->camera()->lens()->setPerspectiveProjection(45.0f, 16.0f / 9.0f, 0.1f, 100.0f);
qt3DWindow->camera()->setPosition(QVector3D(2.5, -8, 0.0));
qt3DWindow->camera()->setViewCenter(QVector3D(0, 0, 0));
// For camera controls
camController->setLinearSpeed(50.f);
camController->setLookSpeed(180.f);
camController->setCamera(qt3DWindow->camera());
// Material
auto *material = new Qt3DExtras::QPhongAlphaMaterial(rootEntity);
material->setSpecular(Qt::white);
material->setShininess(0);
material->setAmbient(Qt::red);
material->setAlpha(0.5);
// Transform
auto *transform = new Qt3DCore::QTransform;
transform->setScale(1.0f);
auto *customMeshEntity = new Qt3DCore::QEntity(rootEntity);
// Custom Mesh
auto *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
auto *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
auto *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry);
auto *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, customGeometry);
// Vertices
auto nVertices = 8;
auto nCoordinates = 3; // cartesian coordinates
QByteArray vertexBufferData;
vertexBufferData.resize(nVertices * nCoordinates * sizeof(float));
auto *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
// Vertex 1
rawVertexArray[0*nCoordinates+0] = 1.0f;
rawVertexArray[0*nCoordinates+1] = 1.0f;
rawVertexArray[0*nCoordinates+2] = 0.0f;
// Vertex 2
rawVertexArray[1*nCoordinates+0] = 0.0f;
rawVertexArray[1*nCoordinates+1] = 1.0f;
rawVertexArray[1*nCoordinates+2] = 0.0f;
// Vertex 3
rawVertexArray[2*nCoordinates+0] = 0.0f;
rawVertexArray[2*nCoordinates+1] = 0.0f;
rawVertexArray[2*nCoordinates+2] = 0.0f;
// Vertex 4
rawVertexArray[3*nCoordinates+0] = 1.0f;
rawVertexArray[3*nCoordinates+1] = 0.0f;
rawVertexArray[3*nCoordinates+2] = 0.0f;
// Vertex 5
rawVertexArray[4*nCoordinates+0] = 1.0f;
rawVertexArray[4*nCoordinates+1] = 0.0f;
rawVertexArray[4*nCoordinates+2] = 1.0f;
// Vertex 6
rawVertexArray[5*nCoordinates+0] = 0.0f;
rawVertexArray[5*nCoordinates+1] = 0.0f;
rawVertexArray[5*nCoordinates+2] = 1.0f;
// Vertex 7
rawVertexArray[6*nCoordinates+0] = 0.0f;
rawVertexArray[6*nCoordinates+1] = 1.0f;
rawVertexArray[6*nCoordinates+2] = 1.0f;
// Vertex 8
rawVertexArray[7*nCoordinates+0] = 1.0f;
rawVertexArray[7*nCoordinates+1] = 1.0f;
rawVertexArray[7*nCoordinates+2] = 1.0f;
vertexDataBuffer->setData(vertexBufferData);
// Faces
unsigned nFaces = 6;
unsigned nIndicesPerFace = 4;
QByteArray indexBufferData;
indexBufferData.resize(nFaces * nIndicesPerFace * sizeof(ushort));
auto *rawIndexArray = reinterpret_cast<ushort *>(indexBufferData.data());
// Face 1
rawIndexArray[0*nIndicesPerFace+0] = 1;
rawIndexArray[0*nIndicesPerFace+1] = 4;
rawIndexArray[0*nIndicesPerFace+2] = 3;
rawIndexArray[0*nIndicesPerFace+3] = 2;
// Face 2
rawIndexArray[1*nIndicesPerFace+0] = 5;
rawIndexArray[1*nIndicesPerFace+1] = 6;
rawIndexArray[1*nIndicesPerFace+2] = 3;
rawIndexArray[1*nIndicesPerFace+3] = 4;
// Face 3
rawIndexArray[2*nIndicesPerFace+0] = 7;
rawIndexArray[2*nIndicesPerFace+1] = 2;
rawIndexArray[2*nIndicesPerFace+2] = 3;
rawIndexArray[2*nIndicesPerFace+3] = 6;
// Face 4
rawIndexArray[3*nIndicesPerFace+0] = 8;
rawIndexArray[3*nIndicesPerFace+1] = 5;
rawIndexArray[3*nIndicesPerFace+2] = 4;
rawIndexArray[3*nIndicesPerFace+3] = 1;
// Face 5
rawIndexArray[4*nIndicesPerFace+0] = 8;
rawIndexArray[4*nIndicesPerFace+1] = 1;
rawIndexArray[4*nIndicesPerFace+2] = 2;
rawIndexArray[4*nIndicesPerFace+3] = 7;
// Face 6
rawIndexArray[5*nIndicesPerFace+0] = 8;
rawIndexArray[5*nIndicesPerFace+1] = 7;
rawIndexArray[5*nIndicesPerFace+2] = 6;
rawIndexArray[5*nIndicesPerFace+3] = 5;
indexDataBuffer->setData(indexBufferData);
// Attributes
auto *positionAttribute = new Qt3DRender::QAttribute();
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(vertexDataBuffer);
positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
positionAttribute->setDataSize(3);
positionAttribute->setByteOffset(0);
positionAttribute->setByteStride(3 * sizeof(float));
positionAttribute->setCount(nVertices);
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
auto *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexDataBuffer);
indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedShort);
indexAttribute->setDataSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(nFaces*nIndicesPerFace);
customGeometry->addAttribute(positionAttribute);
customGeometry->addAttribute(indexAttribute);
customMeshRenderer->setInstanceCount(1);
customMeshRenderer->setFirstVertex(0);
customMeshRenderer->setIndexOffset(1); // first index is 1
customMeshRenderer->setFirstInstance(0);
customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Patches);
customMeshRenderer->setVerticesPerPatch(4);
customMeshRenderer->setGeometry(customGeometry);
customMeshRenderer->setVertexCount(nFaces * nIndicesPerFace);
customMeshEntity->addComponent(customMeshRenderer);
customMeshEntity->addComponent(transform);
customMeshEntity->addComponent(material);
qt3DWindow->setRootEntity(rootEntity);
widget->show();
return QApplication::exec();
}
渲染的场景仍然是空的,所以我认为我在这里做错了什么。 感谢您的帮助!
答案 0 :(得分:2)
OpenGL中的“补丁”具有非常特殊的含义(补丁与tessellation shaders有关,而您并未使用)。
在这里,您只是在处理四边形的面孔。为了渲染它们,您需要将它们分成两个三角形(现代OpenGL不再渲染四边形)。请注意,如果您有一个.obj文件,则可以使用QMesh / QSceneLoader直接加载该文件...
答案 1 :(得分:0)
我制定了解决方案。遵循@peppe的建议,我绘制了三角形。我还计算了顶点法线。
代码在这里:
#include <QApplication>
#include <QWidget>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DRender/QCamera>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DRender/QAttribute>
#include <Qt3DRender/QBuffer>
#include <Qt3DExtras/QPhongAlphaMaterial>
#include <iostream>
#include <assert.h>
#include <utility>
struct Vertex{
Vertex(QVector3D p, ushort id)
: position(p), normal({0,0,0}), index(id){}
QVector3D position, normal;
ushort index;
};
struct Quad{
Quad() = delete;
explicit Quad(std::vector<Vertex> v)
: vertices(v) {
assert(vertices.size() == 4);
}
std::vector<Vertex> vertices;
};
struct Triangle{
Triangle() = delete;
explicit Triangle(std::vector<Vertex> v)
: vertices(v), faceNormal(QVector3D::normal(v[0].position,v[1].position,v[2].position)) {
assert(vertices.size() == 3);
}
std::vector<Vertex> vertices;
QVector3D faceNormal;
};
using trianlgePair = std::pair<Triangle,Triangle>;
trianlgePair quadToTriangle(Quad quad) {
return {Triangle({quad.vertices[0], quad.vertices[1], quad.vertices[2]}),
Triangle({quad.vertices[2], quad.vertices[3], quad.vertices[0]})};
}
int main(int argc, char* argv[])
{
std::vector<Vertex>vertices({
Vertex({1.0f, 1.0f, 0.0f}, 1-1),
Vertex({0.0f, 1.0f, 0.0f}, 2-1),
Vertex({0.0f, 0.0f, 0.0f}, 3-1),
Vertex({1.0f, 0.0f, 0.0f}, 4-1),
Vertex({1.0f, 0.0f, 1.0f}, 5-1),
Vertex({0.0f, 0.0f, 1.0f}, 6-1),
Vertex({0.0f, 1.0f, 1.0f}, 7-1),
Vertex({1.0f, 1.0f, 1.0f}, 8-1)
});
std::vector<Quad> quads({
Quad({vertices[1-1], vertices[4-1], vertices[3-1], vertices[2-1]}),
Quad({vertices[5-1], vertices[6-1], vertices[3-1], vertices[4-1]}),
Quad({vertices[7-1], vertices[2-1], vertices[3-1], vertices[6-1]}),
Quad({vertices[8-1], vertices[5-1], vertices[4-1], vertices[1-1]}),
Quad({vertices[8-1], vertices[1-1], vertices[2-1], vertices[7-1]}),
Quad({vertices[8-1], vertices[7-1], vertices[6-1], vertices[5-1]})
});
unsigned nCoordinates = 3; // cartesian coordinates
// Triangles
std::vector<Triangle> triangles;
for(const auto& quad : quads){
auto trianglePair = quadToTriangle(quad);
triangles.push_back(trianglePair.first);
triangles.push_back(trianglePair.second);
}
unsigned nIndicesPerTriangle= 3;
// vertex normals
for (auto it = vertices.begin(); it != vertices.end(); ++it) {
QVector3D vertexNormal = {0,0,0};
// find triangles that contain the vertex
for(const auto& t : triangles) {
if(std::find_if(t.vertices.begin(), t.vertices.end(),
[it](const Vertex& v)->bool { return v.index == it.base()->index; }
) != t.vertices.end())
vertexNormal += t.faceNormal;
}
it.base()->normal = vertexNormal.normalized();
}
QApplication app(argc, argv);
// Root entity
auto *rootEntity = new Qt3DCore::QEntity();
// Window container
auto qt3DWindow = new Qt3DExtras::Qt3DWindow();
qt3DWindow->setRootEntity(rootEntity);
auto widget = QWidget::createWindowContainer(qt3DWindow);
// Camera
auto *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
qt3DWindow->setRootEntity(rootEntity);
qt3DWindow->camera()->lens()->setPerspectiveProjection(45.0f, 16.0f / 9.0f, 0.1f, 100.0f);
qt3DWindow->camera()->setPosition(QVector3D(2.5, -8, 0.0));
qt3DWindow->camera()->setViewCenter(QVector3D(0, 0, 0));
// For camera controls
camController->setLinearSpeed(50.f);
camController->setLookSpeed(180.f);
camController->setCamera(qt3DWindow->camera());
// Material
auto *material = new Qt3DExtras::QPhongAlphaMaterial(rootEntity);
material->setSpecular(Qt::white);
material->setShininess(0);
material->setAmbient(Qt::red);
material->setAlpha(0.5);
// Transform
auto *transform = new Qt3DCore::QTransform;
transform->setScale(1.0f);
auto *customMeshEntity = new Qt3DCore::QEntity(rootEntity);
// Custom Mesh
auto *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
auto *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
auto *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry);
auto *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, customGeometry);
// Vertices
auto vertexDataPackageSize = nCoordinates*2; // position + normal
QByteArray vertexBufferData;
vertexBufferData.resize(vertices.size() * vertexDataPackageSize * sizeof(float));
auto *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
int idx = 0;
for (const auto & v : vertices) {
rawVertexArray[idx++] = float(v.position[0]);
rawVertexArray[idx++] = float(v.position[1]);
rawVertexArray[idx++] = float(v.position[2]);
rawVertexArray[idx++] = float(v.normal[0]);
rawVertexArray[idx++] = float(v.normal[1]);
rawVertexArray[idx++] = float(v.normal[2]);
}
vertexDataBuffer->setData(vertexBufferData);
auto *positionAttribute = new Qt3DRender::QAttribute();
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(vertexDataBuffer);
positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
positionAttribute->setDataSize(nCoordinates);
positionAttribute->setByteOffset(0);
positionAttribute->setByteStride(vertexDataPackageSize * sizeof(float));
positionAttribute->setCount(vertices.size());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
auto *normalAttribute = new Qt3DRender::QAttribute();
normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
normalAttribute->setBuffer(vertexDataBuffer);
normalAttribute->setDataType(Qt3DRender::QAttribute::Float);
normalAttribute->setDataSize(nCoordinates);
normalAttribute->setByteOffset(nCoordinates * sizeof(float));
normalAttribute->setByteStride(vertexDataPackageSize * sizeof(float));
normalAttribute->setCount(vertices.size());
normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName());
QByteArray indexBufferData;
indexBufferData.resize(triangles.size() * nIndicesPerTriangle * sizeof(ushort));
auto *rawIndexArray = reinterpret_cast<ushort *>(indexBufferData.data());
idx = 0;
for (const auto& t : triangles) {
rawIndexArray[idx++] = t.vertices[0].index;
rawIndexArray[idx++] = t.vertices[1].index;
rawIndexArray[idx++] = t.vertices[2].index;
//std::cout << t.vertices[0].index <<", "<< t.vertices[1].index <<", "<< t.vertices[2].index << std::endl;
}
indexDataBuffer->setData(indexBufferData);
auto *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexDataBuffer);
indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedShort);
indexAttribute->setDataSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(triangles.size()*nIndicesPerTriangle);
customMeshRenderer->setInstanceCount(1);
customMeshRenderer->setFirstVertex(0);
customMeshRenderer->setIndexOffset(0);
customMeshRenderer->setFirstInstance(0);
customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
customMeshRenderer->setGeometry(customGeometry);
customMeshRenderer->setVertexCount(triangles.size()*nIndicesPerTriangle);
customGeometry->addAttribute(positionAttribute);
customGeometry->addAttribute(normalAttribute);
customGeometry->addAttribute(indexAttribute);
customMeshEntity->addComponent(customMeshRenderer);
customMeshEntity->addComponent(transform);
customMeshEntity->addComponent(material);
qt3DWindow->setRootEntity(rootEntity);
widget->show();
return QApplication::exec();
}