openGl绘制五星红旗
目录
- 一、核心思路
- 1. 分析五星红旗各个比例、尺寸
- 1. 红色旗面:
- 2. 五角星:
- 2. 绘制思路
- 二、源码
一、核心思路
1. 分析五星红旗各个比例、尺寸
1. 红色旗面:
长宽比 3:2
2. 五角星:
至于绘制五角星的方法,详情参考我的另一篇博客VS-openGL 绘制五角星
(1)位置与内外接圆半径
前提 将红色旗面等分为四个矩形,再将左上角矩形长等分为15份,宽等分为10份,这里每份大小为单位1,并以左上角的顶点为原点,来记录各个五角星的坐标。
大五角星 圆心(5,-5),外接圆半径R=3,内接圆半径r=1.15;
小五角星 ①(10,-2),②(12,-4),③(12,-7),④(10,-9),外接圆半径R=1,内接圆半径r=0.38
举例:绘制长300宽200的国旗,国旗左上顶点(x,y),则大五角星的属性应当进行如下计算:
将长300的国旗等分为四个矩形,每个矩形的长度为300÷2=150,将矩形等分为15份,每份的大小为150÷15=10,则大五角星的圆心坐标为(x + 5 * 10 , y - 5 * 10),外接圆半径R=3 * 10,内接圆半径r=1.15 * 10。小五角星同理省略…
(2)小五角星指向问题
前提
- 我绘制的五角星,默认有一个外顶点是竖直向上的;
- 五星红旗中四个小五角星都有一个外顶点指向大五角星的圆心;
综上所述:我们需要将绘制出来的部分小五角星进行旋转(去指向大五角星的圆心),为了便于计算旋转的角度,我默认将竖直向上的那个外顶点旋转至指向大五角星的圆心。
旋转角度 每个小五角星都有自己的β角(并固定的某一个角),可以看我给的图片,有标注
- 小五角星①:逆时针旋转180°-β角度,cosβ=3/(根号34),通过cos值,推算β值(通过余弦值计算度数的网站),β=59.3°,旋转度数:180°-59.3°= 120.7°
- 小五角星②:逆时针旋转Π-β角度,cosβ=1/[5*(根号2)],β=81.9°,旋转度数:98.1°
- 小五角星③:不用旋转
- 小五角星④:逆时针旋转β角度,cosβ=4/(根号41),β=51.6°
2. 绘制思路
思路如下:(也是编写代码的思路)
- 绘制红色旗面
- 绘制大五角星
- 绘制小五角星
二、源码
#include <GL/glew.h>//OpenGL扩展库
#include <GL/glut.h>//OpenGL工具库
#include <stdio.h>
#include <math.h>
// 定义Π
#define PI 3.14159265
// 定义坐标结构体
struct Vertex {
double x;
double y;
};
// ####绘制五角星方法####
// 绘制黄色三角形函数
void drawYellowTriangle(Vertex Vertex_Fir, Vertex Vertex_Sec, Vertex Vertex_Thi) {
// 设置填充的颜色
glColor3f(255, 255, 0);
// 设置绘制类型
glBegin(GL_TRIANGLES);
// 第一个坐标
glVertex2f(Vertex_Fir.x, Vertex_Fir.y);
// 第二个坐标
glVertex2f(Vertex_Sec.x, Vertex_Sec.y);
// 第三个坐标
glVertex2f(Vertex_Thi.x, Vertex_Thi.y);
glEnd();
}
// 获取外圆五角星的五顶点(参数:大圆圆心坐标以及半径)
Vertex* getExternalVertex(Vertex Center_Vertex, double R) {
// 定义Vertex结构体数组,包括五个顶点和一个圆心
Vertex* externalVertex = new Vertex[6];
double alpha = 2 * PI / 5;
double thet = PI / 10;
double bet = 2 * PI / 10;
// 圆心坐标
externalVertex[0].x = Center_Vertex.x, externalVertex[0].y = Center_Vertex.y;
// 其余五个顶点
externalVertex[1].x = Center_Vertex.x, externalVertex[1].y = Center_Vertex.y + R;
externalVertex[2].x = Center_Vertex.x + R * cos(thet), externalVertex[2].y = Center_Vertex.y + R * sin(thet);
externalVertex[3].x = Center_Vertex.x + R * sin(bet), externalVertex[3].y = Center_Vertex.y - R * cos(bet);
externalVertex[4].x = Center_Vertex.x - R * sin(bet), externalVertex[4].y = Center_Vertex.y - R * cos(bet);
externalVertex[5].x = Center_Vertex.x - R * cos(thet), externalVertex[5].y = Center_Vertex.y + R * sin(thet);
return externalVertex;
}
// 获取内圆五角星的五顶点(参数:小圆圆心坐标以及半径)
Vertex* getInternalVertex(Vertex Center_Vertex, double r) {
// 定义Vertex结构体数组,包括五个顶点和一个圆心
Vertex* internalVertex = new Vertex[6];
double alpha = 2 * PI / 5;
double thet = PI / 10;
double bet = (PI - alpha) / 2;
// 圆心坐标
internalVertex[0].x = Center_Vertex.x, internalVertex[0].y = Center_Vertex.y;
// 其余五个顶点
internalVertex[1].x = Center_Vertex.x + r * cos(bet), internalVertex[1].y = Center_Vertex.y + r * sin(bet);
internalVertex[2].x = Center_Vertex.x + r * cos(thet), internalVertex[2].y = Center_Vertex.y - r * sin(thet);//
internalVertex[3].x = Center_Vertex.x, internalVertex[3].y = Center_Vertex.y - r;//
internalVertex[4].x = Center_Vertex.x - r * cos(thet), internalVertex[4].y = Center_Vertex.y - r * sin(thet);
internalVertex[5].x = Center_Vertex.x - r * cos(bet), internalVertex[5].y = Center_Vertex.y + r * sin(bet);
return internalVertex;
}
// ####绘制红旗方法####
// 绘制红色矩阵函数
void drawRedRect(Vertex* vertex) {
// 设置绘制类型
glShadeModel(GL_FLAT);
glBegin(GL_POLYGON);
// 设置填充的颜色,默认以第一个点的颜色进行纯色填充
glColor3f(1, 0, 0);
// 第一个坐标
glVertex2f(vertex[0].x, vertex[0].y);
// 第二个坐标
glVertex2f(vertex[1].x, vertex[1].y);
// 第三个坐标
glVertex2f(vertex[2].x, vertex[2].y);
// 第四个坐标
glVertex2f(vertex[3].x, vertex[3].y);
glEnd();
}
// 设置背景颜色
void setBackgroundColor(void) {
glClearColor(0.2, 0.3, 0.3, 0.5);
}
// 绘制国旗
void draw(void) {
// 清除清缓存
glClear(GL_COLOR_BUFFER_BIT);
// ### 一、绘制红色矩形 ###
Vertex* rectVertex=new Vertex[4];
rectVertex[0].x = 10, rectVertex[0].y = 410;//左上角(高1000)
rectVertex[1].x = 10, rectVertex[1].y = 10;//左下角
rectVertex[2].x = 610, rectVertex[2].y = 10;//右下角(宽1500)
rectVertex[3].x = 610, rectVertex[3].y = 410;//右上角
drawRedRect(rectVertex);
// ### 二、绘制五角星 ###
// # <1>大五角星 #
// 1. 定义圆心、大小圆半径
Vertex Center_Vertex;
Center_Vertex.x = 110, Center_Vertex.y = 310;//圆心以显示窗口的左下角为原点,向右x轴正方向,向上y轴正方向
double R = 60;
double r = 23;
// 2. 获取内外顶点
Vertex* externalVertex = getExternalVertex(Center_Vertex, R);
Vertex* internalVertex = getInternalVertex(Center_Vertex, r);
// 3. 绘制黄色五角星
for (int i = 1; i < 6; i++) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i]);
if (i < 5) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i + 1]);
}
else {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[1]);
}
}
// # <2>小五角星① #
// 1. 定义圆心、大小圆半径
Center_Vertex.x = 210, Center_Vertex.y = 370;//圆心以显示窗口的左下角为原点,向右x轴正方向,向上y轴正方向
R = 20;
r = 7.6;
// 2. 获取内外顶点
externalVertex = getExternalVertex(Center_Vertex, R);
internalVertex = getInternalVertex(Center_Vertex, r);
// 3.几何变换(旋转一定角度)
glPushMatrix();//几何变换的边界起点
glTranslatef(210, 370, 0);//移动回初始位置
glRotatef(120.7, 0, 0, 1);//绕z轴旋转,即xoy平面以原点为中心逆时针旋转
glTranslatef(-210, -370, 0);//移动回原点
// 4. 绘制黄色五角星
for (int i = 1; i < 6; i++) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i]);
if (i < 5) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i + 1]);
}
else {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[1]);
}
}
glPopMatrix();//几何变换的边界终点(只对边界内的图形进行几何变换)
// # <3>小五角星② #
// 1. 定义圆心、大小圆半径
Center_Vertex.x = 250, Center_Vertex.y = 330;//圆心以显示窗口的左下角为原点,向右x轴正方向,向上y轴正方向
R = 20;
r = 7.6;
// 2. 获取内外顶点
externalVertex = getExternalVertex(Center_Vertex, R);
internalVertex = getInternalVertex(Center_Vertex, r);
// 3.几何变换(旋转一定角度)
glPushMatrix();//几何变换的边界起点
glTranslatef(250, 330, 0);//移动回初始位置
glRotatef(98.1, 0, 0, 1);//绕z轴旋转,即xoy平面以原点为中心逆时针旋转
glTranslatef(-250, -330, 0);//移动回原点
// 4. 绘制黄色五角星
for (int i = 1; i < 6; i++) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i]);
if (i < 5) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i + 1]);
}
else {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[1]);
}
}
glPopMatrix();//几何变换的边界终点(只对边界内的图形进行几何变换)
// # <4>小五角星③ #
// 1. 定义圆心、大小圆半径
Center_Vertex.x = 250, Center_Vertex.y = 270;//圆心以显示窗口的左下角为原点,向右x轴正方向,向上y轴正方向
R = 20;
r = 7.6;
// 2. 获取内外顶点
externalVertex = getExternalVertex(Center_Vertex, R);
internalVertex = getInternalVertex(Center_Vertex, r);
// 3. 绘制黄色五角星
for (int i = 1; i < 6; i++) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i]);
if (i < 5) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i + 1]);
}
else {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[1]);
}
}
// # <5>小五角星④ #
// 1. 定义圆心、大小圆半径
Center_Vertex.x = 210, Center_Vertex.y = 230;//圆心以显示窗口的左下角为原点,向右x轴正方向,向上y轴正方向
R = 20;
r = 7.6;
// 2. 获取内外顶点
externalVertex = getExternalVertex(Center_Vertex, R);
internalVertex = getInternalVertex(Center_Vertex, r);
// 3.几何变换(旋转一定角度)
glPushMatrix();//几何变换的边界起点
glTranslatef(210, 230, 0);//移动回初始位置
glRotatef(51.6, 0, 0, 1);//绕z轴旋转,即xoy平面以原点为中心逆时针旋转
glTranslatef(-210, -230, 0);//移动回原点
// 4. 绘制黄色五角星
for (int i = 1; i < 6; i++) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i]);
if (i < 5) {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[i + 1]);
}
else {
drawYellowTriangle(Center_Vertex, internalVertex[i], externalVertex[1]);
}
}
glPopMatrix();//几何变换的边界终点(只对边界内的图形进行几何变换)
glutSwapBuffers();//交换缓冲(双缓冲时使用)
}
void reshape(int width, int height)
{
glViewport(0, 0, width, height);//设置视区
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);//设置图形数据范围
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main() {
// 窗口的坐标是电脑屏幕左上角为原点,向右为x轴正方向;向下为y轴正方向
glutInitWindowPosition(10, 10); //定义窗口位置与大小
glutInitWindowSize(1200, 700);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); //初始化显示模式
glutCreateWindow("五星红旗"); //定义窗口名称
setBackgroundColor(); // 设置背景色
glutDisplayFunc(draw); //图形绘制函数
glutReshapeFunc(reshape); //窗口重绘函数
glutMainLoop(); //无限循环函数
return 0;
}
编码中的一些问题与思考 :我绘制的五角星是由多个三角形多次绘画构成的,那么我进行几何变换(旋转)的时候如何让整个五角星都进行旋转,而不是只有其中某个三角进行了旋转?
个人理解的答案 :将需要旋转的图形的绘制代码,放在一个边界之内 (glPushMatrix();),则边界内的才会进行几何变换,边界外的不受影响。
详情参考OpenGL图像平移、旋转基本操作总结