Я разработал решение. Следуя предложению @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();
}