OpenGL(可编程管线):椭圆的绘制和贴图

本文详细介绍了如何使用C++和OpenGL构建一个椭圆类,通过八分法绘制不同类型的椭圆,包括长轴在x轴、y轴以及特殊情况下的圆。代码中实现了将角度转换为弧度的函数,并根据长轴和短轴计算顶点的纹理坐标,以实现不同形状的椭圆。此外,还提供了获取顶点、法线、纹理坐标和索引的方法。
摘要由CSDN通过智能技术生成

在这里插入图片描述
和绘制圆一样的思路,八分法绘制椭圆,借助上面的参数方程,以原点为(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坐标的计算。
在这里插入图片描述
在这里插入图片描述

运行结果

情况一:长轴在x轴

在这里插入图片描述

情况二:长轴在y轴

在这里插入图片描述

情况三:长轴等于短轴(圆)

在这里插入图片描述

OpenGL中,绘制一条直线通常通过设置顶点坐标并调用线段渲染函数GL_LINES来实现。以下是使用C++和GLFW库创建一个基本窗口并在其中绘制直线的一个简单示例: ```cpp #include <GLFW/glfw3.h> #include <GL/glut.h> // 定义顶点结构体 struct Vertex { GLfloat x, y; }; // 线段数据 Vertex vertices[] = {{0.0f, 0.0f}, {1.0f, 0.0f}}; // 直线起点和终点 void draw_line() { glEnable(GL_LINE_SMOOTH); // 启用平滑线条 glVertexPointer(2, GL_FLOAT, sizeof(Vertex), vertices); // 设置顶点指针 glColor3f(1.0f, 0.0f, 0.0f); // 设置红色作为线条颜色 glLineWidth(3.0f); // 设置线条宽度 glDrawArrays(GL_LINES, 0, 2); // 绘制两个顶点之间的线段 } int main() { if (!glfwInit()) { return -1; } GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Line Example", NULL, NULL); if (!window) { glfwTerminate(); return -1; } glfwMakeContextCurrent(window); while (!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT); draw_line(); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; } ``` 这个代码首先包含了必要的头文件,然后定义了一个顶点结构,接着创建了两个顶点代表直线的一端到另一端。`draw_line`函数设置了需要的OpenGL状态,并调用`glDrawArrays`渲染线段。 注意,这个例子假设你已经安装了GLFW和GLUT库,并且你的环境中支持OpenGL。如果你要在实际项目中使用,可能需要替换`glut`为现代的OpenGL库如GLAD或Vulkan,并使用更现代的输入处理方式。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ht巷子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值