和绘制圆一样的思路,八分法绘制椭圆,借助上面的参数方程,以原点为(0,0)为例,上代码:
椭圆的绘制
- 构建椭圆类
- 代码解释
- 运行结果
- 情况一:长轴在x轴
- 情况二:长轴在y轴
- 情况三:长轴等于短轴(圆)
构建椭圆类
#pragma once
#include <vector>
#include <glm\glm.hpp>
using namespace std;
class Ellipse
{
private:
//顶点
vector<glm::vec3> vertices;
//法线
vector<glm::vec3> normals;
//纹理坐标
vector<glm::vec2> texCoords;
//索引
vector<int> indices;
//顶点个数
int numVertices;
//索引个数
int numIndices;
//长轴,x轴
float longAxis;
//短轴,y轴
float shortAxis;
void init(int prec);
public:
Ellipse();
Ellipse(float longAxis, float shortAxis, int prec);
float toRadians(float degrees);
vector<glm::vec3> getVertices();
vector<glm::vec3> getNormals();
vector<glm::vec2> getTexCoords();
vector<int> getIndices();
int getNumVertices();
int getNumIndices();
};
#include "Ellipse.h"
Ellipse::Ellipse()
{
}
Ellipse::Ellipse(float longAxis, float shortAxis, int prec)
{
this->longAxis = longAxis;
this->shortAxis = shortAxis;
init(prec);
}
float Ellipse::toRadians(float degrees) {
float pi = acos(-1.0);
return (degrees * 2.0f * pi) / 360.0f;
}
void Ellipse::init(int prec)
{
numVertices = prec + 1;
numIndices = prec * 3;
for (int i = 0; i < numVertices; i++)
{
vertices.push_back(glm::vec3());
normals.push_back(glm::vec3());
texCoords.push_back(glm::vec2(0.5f, 0.25f));
}
for (int i = 0; i < numIndices; i++)
{
indices.push_back(0);
}
for (int i = 0; i < prec; i++)
{
float degrees, radians;
if (i < prec / 2)
{
degrees = i * 360.f / (prec / 2);
radians = toRadians(degrees);
}
else
{
degrees = -((i - prec / 2) * 360.f) / (prec / 2);
radians = toRadians(degrees);
}
float x = longAxis * cos(radians);
float y = shortAxis * sin(radians);
float s, t;
vertices[i] = glm::vec3(x, y, 0.f);
normals[i] = glm::vec3(1.0f, 1.f, 1.f);
float product;
if (longAxis > shortAxis)
{
product = shortAxis / (2 * longAxis);
if (x >= 0)
{
s = 0.5 + x / (2 * longAxis);
}
else
{
s = 0.5 - (fabsf(x) / (2 * longAxis));
}
if (y >= 0)
{
t = product + y / (2 * longAxis);
}
else {
t = product - fabsf(y / (2 * longAxis));
}
}
else
{
product = longAxis / (2 * shortAxis);
if (x >= 0)
{
s = product + x / (2 * shortAxis);
}
else
{
s = product - (fabsf(x) / (2 * shortAxis));
}
if (y >= 0)
{
t = 0.5 + y / (2 * shortAxis);
}
else {
t = 0.5 - fabsf(y / (2 * shortAxis));
}
}
texCoords[i] = glm::vec2(s, t);
}
for (int i = 0; i < prec; i++)
{
if (i == prec - 1)
{
indices[3 * i + 0] = i;
indices[3 * i + 1] = 0;
indices[3 * i + 2] = prec;
break;
}
indices[3 * i + 0] = i;
indices[3 * i + 1] = i + 1;
indices[3 * i + 2] = prec;
}
}
vector<glm::vec3> Ellipse::getVertices()
{
return vertices;
}
vector<glm::vec3> Ellipse::getNormals()
{
return normals;
}
vector<glm::vec2> Ellipse::getTexCoords()
{
return texCoords;
}
vector<int> Ellipse::getIndices()
{
return indices;
}
int Ellipse::getNumVertices()
{
return numVertices;
}
int Ellipse::getNumIndices()
{
return numIndices;
}
代码解释
if (longAxis > shortAxis)
{
product = shortAxis / (2 * longAxis);
if (x >= 0)
{
s = 0.5 + x / (2 * longAxis);
}
else
{
s = 0.5 - (fabsf(x) / (2 * longAxis));
}
if (y >= 0)
{
t = product + y / (2 * longAxis);
}
else {
t = product - fabsf(y / (2 * longAxis));
}
}
else
{
product = longAxis / (2 * shortAxis);
if (x >= 0)
{
s = product + x / (2 * shortAxis);
}
else
{
s = product - (fabsf(x) / (2 * shortAxis));
}
if (y >= 0)
{
t = 0.5 + y / (2 * shortAxis);
}
else {
t = 0.5 - fabsf(y / (2 * shortAxis));
}
}
texCoords[i] = glm::vec2(s, t);
}
此段代码中的判断代表了两种情况的椭圆,一种是x轴向为长轴,y轴向为短轴,另一种则是x轴向为短轴,y轴向为长轴的uv坐标的计算。