2021SC@SDUSC
1.buildBoundingBoxMeshEdges函数
此函数根据输入的元素为元组的容器boxes的引用以及指针edgeVerticesNum来生成构建包围盒网格结构的边顶点信息。
//包围盒网格结构
ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes,
int *edgeVerticesNum)
{
//tuple为元组,boxes是元素为元组的容器
int numPerItem = 12 * 2;
//包围盒有12条边,一条边关联着两个顶点
*edgeVerticesNum = boxes.size() * numPerItem;
auto generateForBox = [&](const std::tuple<QVector3D, QVector3D, float, float, QColor> &box, ShaderVertex *vertices) {
const auto &headPosition = std::get<0>(box);
const auto &tailPosition = std::get<1>(box);
float headRadius = std::get<2>(box);
float tailRadius = std::get<3>(box);
const auto &color = std::get<4>(box);
//元组中元素分别代表头节点、尾节点位置,头节点半径,尾节点半径以及颜色
QVector3D direction = tailPosition - headPosition;
QVector3D cutNormal = direction.normalized();
QVector3D baseNormal = choosenBaseAxis(cutNormal);
//util.cpp,baseNormal是与cutNormal最近似垂直的坐标
QVector3D u = QVector3D::crossProduct(cutNormal, baseNormal).normalized();
//u、cutNormal、baseNormal相互垂直
QVector3D v = QVector3D::crossProduct(u, cutNormal).normalized();
//u、v、cutNormal相互垂直
auto uHeadFactor = u * headRadius;
auto vHeadFactor = v * headRadius;
auto uTailFactor = u * tailRadius;
auto vTailFactor = v * tailRadius;
const std::vector<QVector2D> cutFaceTemplate = {QVector2D((float)-1.0, (float)-1.0),
QVector2D((float)1.0, (float)-1.0),
QVector2D((float)1.0, (float)1.0),
QVector2D((float)-1.0, (float)1.0)
};
std::vector<QVector3D> resultHeadCut;
for (const auto &t: cutFaceTemplate) {
resultHeadCut.push_back(uHeadFactor * t.x() + vHeadFactor * t.y());
}
std::vector<QVector3D> resultTailCut;
for (const auto &t: cutFaceTemplate) {
resultTailCut.push_back(uTailFactor * t.x() + vTailFactor * t.y());
}
//各延伸出四个方向
std::vector<QVector3D> headRing;
std::vector<QVector3D> tailRing;
std::vector<QVector3D> finalizedPoints;
for (const auto &it: resultHeadCut) {
headRing.push_back(it + headPosition);
}
for (const auto &it: resultTailCut) {
tailRing.push_back(it + tailPosition);
}
//以头节点和尾节点为中心延伸四个方向
for (size_t i = 0; i < headRing.size(); ++i) {
finalizedPoints.push_back(headRing[i]);
finalizedPoints.push_back(headRing[(i + 1) % headRing.size()]);
}
for (size_t i = 0; i < tailRing.size(); ++i) {
finalizedPoints.push_back(tailRing[i]);
finalizedPoints.push_back(tailRing[(i + 1) % tailRing.size()]);
}
for (size_t i = 0; i < headRing.size(); ++i) {
finalizedPoints.push_back(headRing[i]);
finalizedPoints.push_back(tailRing[i]);
}
//向finalizedPoints中添加网格信息
for (size_t i = 0; i < finalizedPoints.size(); ++i) {
const auto &sourcePosition = finalizedPoints[i];
ShaderVertex ¤tVertex = vertices[i];
currentVertex.posX = sourcePosition.x();
currentVertex.posY = sourcePosition.y();
currentVertex.posZ = sourcePosition.z();
currentVertex.texU = 0;
currentVertex.texV = 0;
currentVertex.colorR = color.redF();
currentVertex.colorG = color.greenF();
currentVertex.colorB = color.blueF();
currentVertex.normX = 0;
currentVertex.normY = 1;
currentVertex.normZ = 0;
currentVertex.metalness = Model::m_defaultMetalness;
currentVertex.roughness = Model::m_defaultRoughness;
currentVertex.tangentX = 0;
currentVertex.tangentY = 0;
currentVertex.tangentZ = 0;
}
//为currentVertex加入坐标、uv、颜色、法向等信息
};
ShaderVertex *edgeVertices = new ShaderVertex[*edgeVerticesNum];
int vertexIndex = 0;
for (const auto &box: boxes) {
generateForBox(box, &edgeVertices[vertexIndex]);
vertexIndex += numPerItem;
}
//将包围盒中的信息整合在一起
*edgeVerticesNum = vertexIndex;
return edgeVertices;
}
函数中使用到了util.cpp中的choosenBaseAxis函数,此函数的作用是返回x、y、z轴中与输入向量最接近垂直的轴向。具体如下:
QVector3D choosenBaseAxis(const QVector3D &layoutDirection)
{
const std::vector<QVector3D> axisList = {
QVector3D(1, 0, 0),
QVector3D(0, 1, 0),
QVector3D(0, 0, 1),
};
std::vector<std::pair<float, size_t>> dots;
for (size_t i = 0; i < axisList.size(); ++i) {
dots.push_back(std::make_pair(qAbs(QVector3D::dotProduct(layoutDirection, axisList[i])), i));
}
//求layoutDirection在各坐标轴的分量,存到dots中
return axisList[std::min_element(dots.begin(), dots.end(), [](const std::pair<float, size_t> &first,
const std::pair<float, size_t> &second) {
return first.first < second.first;
})->second];
//返回layoutDirection分量最小的坐标轴(与其最垂直)
}
函数的返回值类型为ShaderVertex结构的指针,便于之后与渲染管线进行交互,关于ShaderVertex结构体的介绍如下:
typedef struct
{
GLfloat posX;
GLfloat posY;
GLfloat posZ;
GLfloat normX;
GLfloat normY;
GLfloat normZ;
GLfloat colorR;
GLfloat colorG;
GLfloat colorB;
GLfloat texU;
GLfloat texV;
GLfloat metalness;
GLfloat roughness;
GLfloat tangentX;
GLfloat tangentY;
GLfloat tangentZ;
GLfloat alpha = 1.0;
} ShaderVertex;
位置信息 | posX、posY、posZ |
法线信息 | normX、normY、normZ |
颜色信息 | colorR、colorG、colorB、透明度alpha |
贴图信息 | texU、texV |
材质信息 | metalness、roughness |
切线信息 | tangentX、tangentY、tangentZ |
2.buildBoundingBoxMesh函数
此函数使用了上述buildBoundingBoxMeshEdges函数对包围盒的网格结构进行了构造,然后通过model.h的构造函数:
Model(ShaderVertex *triangleVertices, int vertexNum, ShaderVertex *edgeVertices=nullptr, int edgeVertexCount=0);
对网格进行了构造
Model *buildBoundingBoxMesh(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes)
{
int edgeVerticesNum = 0;
ShaderVertex *edgeVertices = buildBoundingBoxMeshEdges(boxes, &edgeVerticesNum);
return new Model(nullptr, 0, edgeVertices, edgeVerticesNum);
}