继上篇之后本文给出将点数据导出为三角形图元的方法,分配随机颜色并渲染后如图一:
《图一》
因为上篇给出了源代码下载地址,所以这里就只贴出本篇需要修改的两处源文件:
首先是CSphere类的头文件:
////////////////////////////////////////////////////////////
// GLsphere.h
//
////////////////////////////////////////////////////////////
#pragma once
#include "stdafx.h"
#include <vector>
using std::vector;
// 浮点向量
struct VECTOR_F{
VECTOR_F(const float &xparam, const float &yparam, const float &zparam)
:x(xparam), y(yparam), z(zparam)
{}
float x, y, z;
};
// 3维点
struct POINT3D_F{
float x, y, z;
POINT3D_F *a, *b, *c, *d, *e, *f;
};
// 3维三角形
struct TRIANGLE_F{
// 三个顶点
POINT3D_F *a, *b, *c;
// 三角形相对于圆心法线,单位向量
float normal[3];
};
class CSphere{
public:
CSphere(const int &detialLevel, const float &sphereSize);
~CSphere();
void release();
bool isSuccess() { return issuccess; }
private:
int private_power(const int &m, const int &n); // 求冪
// 计算指定复杂度存储所有顶点需要的行数
int private_calNumofRows(const int &detailLevel);
// 计算指定复杂度下某行顶点数量
int private_calPointsoftheRow(const int &detailLevel, const int &rowNumber);
// 计算指定复杂度下某行三角形数量
int private_calTriangleoftheRow(const int &dl, const int &rowNumber);
int private_calRowX(const int &detailLevel);
// 取得vector<POINT3D_F*>指定索引元素的迭代器(非安全)
vector<POINT3D_F*>::iterator private_getVectorofPoints_iterator(vector<POINT3D_F*> &pointsArray,int &index);
// 取得vector<vector<POINT3D_F*>>指定索引数组的迭代器(非安全)
vector<vector<POINT3D_F*>>::iterator private_getVectorofVectorofPoints_iterator(
vector<vector<POINT3D_F*>> &vectorArray, int &index
);
// 取得指定点的编号A邻居
POINT3D_F* private_getNeighborA(int curDL, int rowindex, int elementindex);
// 取得指定点的编号B邻居
POINT3D_F* private_getNeighborB(int curDL, int rowindex, int elementindex);
// 取得指定点的编号C邻居
POINT3D_F* private_getNeighborC(int curDL, int rowindex, int elementindex);
// 取得指定点的编号D邻居
POINT3D_F* private_getNeighborD(int curDL, int rowindex, int elementindex);
// 取得指定点的编号E邻居
POINT3D_F* private_getNeighborE(int curDL, int rowindex, int elementindex);
// 取得指定点的编号F邻居
POINT3D_F* private_getNeighborF(int curDL, int rowindex, int elementindex);
// 计算两向量的中间向量
VECTOR_F private_calMidVector(const VECTOR_F &v1, const VECTOR_F &v2);
// 根据三角形三个顶点计算三角形法线
void private_initTriangleNormal(TRIANGLE_F *triangle);
public:
bool issuccess; // 是否初始化成功
int dl;
float size;
int pointsCount; // 顶点数量:6+(n-1)*3
vector<vector<POINT3D_F *>> points;
int trianglesCount; // 三角形数量:4^detailLevel
vector<vector<TRIANGLE_F*>> triangles;
};
CSphere类的源文件:
////////////////////////////////////////////////////////////
// GLsphere.cpp
//
////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "GLsphere.h"
/*
* 构造
* @detailLevel:细分等级,大于等于2
* @size:球半径
*/
CSphere::CSphere(const int &detailLevel, const float &sphereSize)
:dl(0), size(0.0f), pointsCount(0), trianglesCount(0)
{
if ( (detailLevel < 2)||(sphereSize <= 0.0f) )
{
issuccess = false;
}else{
dl = detailLevel;
size = sphereSize;
// 手动插入当复杂度为1时的点
vector<POINT3D_F *> temp;
points.push_back(temp);
points.push_back(temp);
points.push_back(temp);
POINT3D_F *newpoint = nullptr;
// 上
newpoint = (POINT3D_F*)malloc(sizeof(POINT3D_F));
newpoint->x = newpoint->z = 0.0f;
newpoint->y = size;
points[0].push_back(newpoint);
// 前
newpoint = (POINT3D_F*)malloc(sizeof(POINT3D_F));
newpoint->x = newpoint->y = 0.0f;
newpoint->z = size;
points[1].push_back(newpoint);
// 右
newpoint = (POINT3D_F*)malloc(sizeof(POINT3D_F));
newpoint->y = newpoint->z = 0.0f;
newpoint->x = size;
points[1].push_back(newpoint);
// 后
newpoint = (POINT3D_F*)malloc(sizeof(POINT3D_F));
newpoint->x = newpoint->y = 0.0f;
newpoint->z = -size;
points[1].push_back(newpoint);
// 左
newpoint = (POINT3D_F *)malloc(sizeof(POINT3D_F));
newpoint->y = newpoint->z = 0.0f;
newpoint->x = -size;
points[1].push_back(newpoint);
// 下
newpoint = (POINT3D_F*)malloc(sizeof(POINT3D_F));
newpoint->x = newpoint->z = 0.0f;
newpoint->y = -size;
points[2].push_back(newpoint);
// 开始插值,递增复杂度
for (int curDL = 2; curDL <= dl;++curDL)
{
// 第一步:对已存在的行进行插值
int rowMax = private_calNumofRows(curDL-1) - 2;
// 开始逐行插值
for (int rowindex = 1; rowindex <= rowMax;++rowindex)
{
// 逐行间隔插入新点
for (int elementindex = 0; (unsigned)elementindex < points[rowindex].size(); ++++elementindex)
{
// 初始化一个新点
newpoint = (POINT3D_F *)malloc(sizeof(POINT3D_F));
int lindex = elementindex;
int rindex = (elementindex + 1) % points[rowindex].size();
VECTOR_F newv = private_calMidVector(
VECTOR_F( points[rowindex][lindex]->x, points[rowindex][lindex]->y, points[rowindex][lindex]->z ),
VECTOR_F( points[rowindex][rindex]->x, points[rowindex][rindex]->y, points[rowindex][rindex]->z )
);
// 根据圆心到点有向线段的单位向量计算点的坐标
newpoint->x = newv.x * size;
newpoint->y = newv.y * size;
newpoint->z = newv.z * size;
// 插入点
points[rowindex].insert(private_getVectorofPoints_iterator(points[rowindex], elementindex) + 1, newpoint);
}
}
// 第二步:插入整行的点
rowMax = private_calNumofRows(curDL) - 1;
for (int rowindex = 0; rowindex < rowMax;)
{
// 在当前行索引之后插入一个空行,并递增索引指向新插入的行
++rowindex; // rowindex指向新插入的行
points.insert(private_getVectorofVectorofPoints_iterator(points, rowindex), temp);
// 初始化当前行
int elementMax = private_calPointsoftheRow(curDL, rowindex);
int preElementMax = private_calPointsoftheRow(curDL, rowindex-1 );
int nextElementMax = private_calPointsoftheRow(curDL, rowindex+1 );
for (int elementindex = 0; elementindex < elementMax; ++elementindex)
{
POINT3D_F *prePoint = nullptr;
POINT3D_F *nextP