实验目的与要求
- 掌握Visual Studio Community 2019集成开发环境的安装;掌握CMake跨平台构建工具的安装;掌握Git版本控制工具的安装;掌握vcpkg库管理工具的安装;掌握系统环境变量的设置;了解和掌握OpenGL的环境配置;掌握OpenGL工程项目的建立和基本设置。
- 理解OpenGL的原理;了解和熟悉OpenGL着色语言;掌握基于OpenGL的C++程序结构;掌握OpenGL中若干基本二维图形的绘制;了解顶点着色器的使用;了解片元着色器的使用。
- 使用现代OpenGL中的着色器,绘制多个简单的二维图形,形状内容不限,自己发挥。
实验过程及内容
一.配置环境
1.安装VS(实验前已安装)
2.安装cmake
3.安装git(实验前已安装)
4.使用git从github上安装vcpkg
a) 运行目录下的bootstrap引导脚本,执行 .\bootstrap-vcpkg.bat,构建vcpkg。
b) 执行.\vcpkg integrate install命令,将vcpkg聚合到visual stuido
c) 测试vcpkg是否安装成功,打开cmd,键入vcpkg,出现以下提示,说明vcpkg已配置成功
5.设置系统环境变量
6.安装OpenGL库: GLFW,GLAD,GLM
在命令行中输入命令 vcpkg install glfw3 glad glm,等待安装完成即可
7. 以上环境配置安装完成之后,打开实验1.1_参考代码
a) 点击”main”项目,将其设置为启动项。
b) 点击“本地Windows调试器”编译运行程序
c) 屏幕上成功出现一个红色三角形,说明环境配置成功。
二.OpenGL与着色器编程
1.执行实验1.2留空代码之后,得到下图结果
2. 修改给定代码中生成三角形的函数,实现三角形的效果
原代码:
修改后:
运行代码:
3. 修改给定代码中生成正方形的函数,实现正方形的效果
a) 观察要实现的效果发现需要绘制6个正方形,且黑白相间
故思路为: 利用for循环,生成几个嵌套的正方形,每次绘制完正方形后,正方形的大小变小,然后更改绘制颜色。
b) 修改代码,运行代码
原代码:
修改后的代码:
运行代码:
运行结果与预期结果一致,完成本部分实验。
三.绘制圆和椭圆
1.观察以下代码
发现当参数verticalScale的值为1时,图形将填充为渐变的红色。即当verticalScale不为1时为红色椭圆。
2. 修改VAO数目,增加椭圆和圆,故数目由3改为5
3. 定义椭圆和圆形上的点和颜色
4. 生成椭圆和圆形上的点和颜色
5. 初始化椭圆的数据
6. 初始化圆的数据
7. 绘制椭圆和圆
8. 运行代码,效果如下,与实验要求一致,顺利完成实验。
四.设计自己的几何图形
1.图形构思
构思图形这块想了很久都没想到要绘制什么图案,最后拿出平板,打开笔记软件,绘制出了一个还算像样的图案。构思图案如下:
最终图案与构思版有所区别,但大致形状基本一致,我把作品取名为《几何之脸》,因为图案由简单的图形组成,且有脸型,故以之命名。
2. 绘制思路
图案由正方形,圆形,椭圆形,三角形组成,定义之后按照一定顺序绘制即可了,然后再考虑颜色问题,中间在绘制的过程中踩雷了,因为一些先绘制的图案把原来的图案遮住了,所以绘制顺序很重要。
3. 绘制脸庞
4. 绘制耳朵,嘴巴
三角形不同颜色的特判操作:
5. 绘制眼睛,眼珠
眼睛和眼珠的大小不同:
眼睛和眼珠的颜色不同:
6. 绘制鼻子,头发
头发为红色过渡到白色,鼻子为变化色(根据角度生成颜色)
7. 绘制顺序如下
8. 最终作品
实验结论
- a) 在实验1.1中,我完成了OpenGL环境的配置,成功编译并运行了程序,在屏幕上成功地运行出一个红色的三角形
b) 在实验1.2中, 我补全了代码,调整了三角形的角度,生成了多个嵌套,颜色黑白相间的正方形。
c) 在本次实验中,我补充了绘制椭圆和圆的代码,同时还设计了一个自定义的几何形状图片。 - 本次实验踩了几个坑,一是配置环境时,vcpkg版本的问题,最后通过直接在github上下载解决;二是在绘制不同图形时,需要确保正确的绘制顺序,否则一些图形会被其他图形遮住。
- 通过这次实验,我了解了OpenGL的基本概念和工作原理,包括顶点着色器和片段着色器的使用,学会了OpenGL中绘制简单图形的方法和技巧。
实验代码
实验1.2
#include "Angel.h"
#include <string>
const glm::vec3 WHITE(1.0, 1.0, 1.0);
const glm::vec3 BLACK(0.0, 0.0, 0.0);
const glm::vec3 RED(1.0, 0.0, 0.0);
const glm::vec3 GREEN(0.0, 1.0, 0.0);
const glm::vec3 BLUE(0.0, 0.0, 1.0);
const int TRIANGLE_NUM_POINTS = 3;
const int SQUARE_NUM = 6;
const int SQUARE_NUM_POINTS = 4 * SQUARE_NUM; // 获得三角形的每个角度
double getTriangleAngle(int point) {
return 2 * M_PI / 3 * point;
}
// 获得正方形的每个角度
double getSquareAngle(int point) {
return M_PI / 4 + (M_PI / 2 * point);
}
// 生成三角形上的每个点
void generateTrianglePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex)
{
// 三角形尺寸
glm::vec2 scale(0.25, 0.25);
// 三角形中心位置
glm::vec2 center(0.0, 0.70);
for (int i = 0; i < 3; i++) {
// 当前顶点对应的角度
double currentAngle = getTriangleAngle(i) + M_PI / 2;
// 根据角度及三角形中心计算顶点坐标
vertices[startVertexIndex + i] = glm::vec2(cos(currentAngle), sin(currentAngle)) * scale + center;
}
// 确定三个顶点的颜色
colors[startVertexIndex] = RED;
colors[startVertexIndex + 1] = BLUE;
colors[startVertexIndex + 2] = GREEN;
}
// 生成正方形上的每个点
void generateSquarePoints(glm::vec2 vertices[], glm::vec3 colors[], int squareNum, int startVertexIndex)
{
// 最大正方形尺寸
glm::vec2 scale(0.90, 0.90);
// 正方形中心位置
glm::vec2 center(0.0, -0.25);
glm::vec3 currentColor = WHITE;
int vertexIndex = startVertexIndex;
// 根据正方形及顶点对应角度,计算当前正方形四个顶点坐标
for(int i = 0; i < SQUARE_NUM; i++){
for (int j = 0; j < 4; j++){
double currentAngle = getSquareAngle(j);
vertices[vertexIndex] = glm::vec2(cos(currentAngle), sin(currentAngle)) * scale + center;
colors[vertexIndex] = currentColor;
vertexIndex++;
}
scale -= (0.15, 0.15);
if(i % 2){
currentColor = WHITE;
}else{
currentColor = BLACK;
}
}
}
// 全局变量,两个vao,一个绘制三角形,一个绘制正方形
GLuint vao[2], program;
void init()
{
// 定义三角形的三个点
glm::vec2 triangle_vertices[TRIANGLE_NUM_POINTS];
glm::vec3 triangle_colors[TRIANGLE_NUM_POINTS];
// 定义矩形的点
glm::vec2 square_vertices[SQUARE_NUM_POINTS];
glm::vec3 square_colors[SQUARE_NUM_POINTS];
// 调用生成形状顶点位置的函数
generateTrianglePoints(triangle_vertices, triangle_colors, 0);
generateSquarePoints(square_vertices, square_colors, SQUARE_NUM, 0);
// 读取着色器并使用
std::string vshader, fshader;
vshader = "shaders/vshader.glsl";
fshader = "shaders/fshader.glsl";
program = InitShader(vshader.c_str(), fshader.c_str());
glUseProgram(program);
/*
* 初始化三角形的数据
*/
// 创建顶点数组对象
glGenVertexArrays(1, &vao[0]); // 分配1个顶点数组对象
glBindVertexArray(vao[0]); // 绑定顶点数组对象
// 创建顶点缓存对象,vbo[2]是因为我们将要使用两个缓存对象,
// 一个是顶点坐标,一个是顶点颜色
GLuint vbo[2];
// 分配1个顶点缓存对象
glGenBuffers(1, &vbo[0]);
// 绑定顶点缓存对象
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// 分配数据所需的存储空间,将数据拷贝到OpenGL服务端内存
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);
// 从顶点着色器中初始化顶点的位置
GLuint location = glGetAttribLocation(program, "vPosition");
// 启用顶点属性数组
glEnableVertexAttribArray(location);
// 关联到顶点属性数组 (index, size, type, normalized, stride, *pointer)
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
// 给颜色
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_colors), triangle_colors, GL_STATIC_DRAW);
GLuint cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
/*
* 初始化正方形的数据
*/
// 创建顶点数组对象
glGenVertexArrays(1, &vao[1]); // 分配1个顶点数组对象
glBindVertexArray(vao[1]); // 绑定顶点数组对象
// 创建顶点缓存对象,我们可以重复使用我们声明的vbo变量
// 正方形顶点坐标
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertices), square_vertices, GL_STATIC_DRAW);
// 从顶点着色器中初始化顶点的位置
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
// 正方形颜色
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_colors), square_colors, GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
// 黑色背景
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void display(void)
{
// 清理窗口
glClear(GL_COLOR_BUFFER_BIT);
// 激活着色器
glUseProgram(program);
// 绑定三角形的顶点数组对象
glBindVertexArray(vao[0]);
glDrawArrays(GL_TRIANGLES, 0, TRIANGLE_NUM_POINTS);
// 绑定正方形的顶点数组对象
glBindVertexArray(vao[1]);
// 注意这里使用的绘制模式为GL_TRIANGLE_FAN
// 它会以顶点数据的一个点为中心顶点,绘制三角形
// 绘制多个正方形
for (int i = 0; i < SQUARE_NUM; ++i) {
glDrawArrays(GL_TRIANGLE_FAN, (i * 4), 4);
}
// 强制所有进行中的OpenGL命令完成
glFlush();
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main(int argc, char** argv)
{
// 初始化GLFW库,必须是应用程序调用的第一个GLFW函数
glfwInit();
// 配置GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// 配置窗口属性
GLFWwindow* window = glfwCreateWindow(512, 512, "Red Triangle", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 调用任何OpenGL的函数之前初始化GLAD
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
init();
// 指定当前窗口进行重绘时要调用的函数
while (!glfwWindowShouldClose(window))
{
display();
// 交换颜色缓冲 以及 检查有没有触发什么事件(比如键盘输入、鼠标移动等)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
return 0;
}
// 每当窗口改变大小,GLFW会调用这个函数并填充相应的参数供你处理。
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
补充圆和椭圆
#include "Angel.h"
#include <string>
const glm::vec3 WHITE(1.0, 1.0, 1.0);
const glm::vec3 BLACK(0.0, 0.0, 0.0);
const glm::vec3 RED(1.0, 0.0, 0.0);
const glm::vec3 GREEN(0.0, 1.0, 0.0);
const glm::vec3 BLUE(0.0, 0.0, 1.0);
const int CIRCLE_NUM_POINTS = 100;
const int ELLIPSE_NUM_POINTS = 100;
const int TRIANGLE_NUM_POINTS = 3;
const int SQUARE_NUM = 6;
const int SQUARE_NUM_POINTS = 4 * SQUARE_NUM;
const int LINE_NUM_POINTS = 2;
// 每当窗口改变大小,GLFW会调用这个函数并填充相应的参数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// 根据角度生成颜色
float generateAngleColor(double angle)
{
return 1.0 / (2 * M_PI) * angle;
}
// 获得三角形的每个角度
double getTriangleAngle(int point)
{
return 2 * M_PI / 3 * point;
}
// 获得正方形的每个角度
double getSquareAngle(int point)
{
return M_PI / 4 + (M_PI / 2 * point);
}
// 计算椭圆/圆上的点
glm::vec2 getEllipseVertex(glm::vec2 center, double scale, double verticalScale, double angle)
{
glm::vec2 vertex(sin(angle), cos(angle));
vertex *= scale;
vertex.y *= verticalScale;
vertex += center;
return vertex;
}
// 获得三角形的每个顶点
void generateTrianglePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex)
{
glm::vec2 scale(0.25, 0.25);
glm::vec2 center(0.0, 0.70);
for (int i = 0; i < 3; ++i) {
double currentAngle = getTriangleAngle(i);
vertices[startVertexIndex + i] = glm::vec2(sin(currentAngle), cos(currentAngle)) * scale + center;
}
colors[startVertexIndex] = RED;
colors[startVertexIndex + 1] = GREEN;
colors[startVertexIndex + 2] = BLUE;
}
// 获得正方形的每个顶点
void generateSquarePoints(glm::vec2 vertices[], glm::vec3 colors[], int squareNumber, int startVertexIndex)
{
glm::vec2 scale(0.90, 0.90);
double scaleDecrease = 0.15;
glm::vec2 center(0.0, -0.25);
int vertexIndex = startVertexIndex;
for (int i = 0; i < squareNumber; ++i) {
glm::vec3 currentColor;
currentColor = (i % 2) ? BLACK : WHITE;
for (int j = 0; j < 4; ++j) {
double currentAngle = getSquareAngle(j);
vertices[vertexIndex] = glm::vec2(sin(currentAngle), cos(currentAngle)) * scale + center;
colors[vertexIndex] = currentColor;
vertexIndex++;
}
scale -= scaleDecrease;
}
}
// 获得线的顶点
void generateLinePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex)
{
vertices[startVertexIndex] = glm::vec2(-1.0, -1.0);
vertices[startVertexIndex + 1] = glm::vec2(1.0, 1.0);
colors[startVertexIndex] = WHITE;
colors[startVertexIndex + 1] = BLUE;
}
// 获得椭圆/圆的每个顶点
void generateEllipsePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex, int numPoints,
glm::vec2 center, double scale, double verticalScale)
{
double angleIncrement = (2 * M_PI) / numPoints;
double currentAngle = M_PI / 2;
for (int i = startVertexIndex; i < startVertexIndex + numPoints; ++i) {
vertices[i] = getEllipseVertex(center, scale, verticalScale, currentAngle);
if (verticalScale == 1.0) {
colors[i] = glm::vec3(generateAngleColor(currentAngle), 0.0, 0.0);
}
else {
colors[i] = RED;
}
currentAngle += angleIncrement;
}
}
// 将3改为5,因为多了椭圆和圆
// GLuint vao[3], program;
GLuint vao[5], program;
void init()
{
// 定义三角形的点
glm::vec2 triangle_vertices[TRIANGLE_NUM_POINTS];
glm::vec3 triangle_colors[TRIANGLE_NUM_POINTS];
// 定义矩形的点
glm::vec2 square_vertices[SQUARE_NUM_POINTS];
glm::vec3 square_colors[SQUARE_NUM_POINTS];
// 定义线的点
glm::vec2 line_vertices[LINE_NUM_POINTS];
glm::vec3 line_colors[LINE_NUM_POINTS];
// 定义椭圆的点
glm::vec2 ellipse_vertices[ELLIPSE_NUM_POINTS];
glm::vec3 ellipse_colors[ELLIPSE_NUM_POINTS];
// 定义圆的点
glm::vec2 circle_vertices[CIRCLE_NUM_POINTS];
glm::vec3 circle_colors[CIRCLE_NUM_POINTS];
// @TODO: 生成圆形和椭圆上的点和颜色
// 调用生成形状顶点位置的函数
generateTrianglePoints(triangle_vertices, triangle_colors, 0);
generateSquarePoints(square_vertices, square_colors, SQUARE_NUM, 0);
generateLinePoints(line_vertices, line_colors, 0);
generateEllipsePoints(ellipse_vertices, ellipse_colors, 0, ELLIPSE_NUM_POINTS,glm::vec2(-0.6, 0.7), 0.25, 0.5);
generateEllipsePoints(circle_vertices, circle_colors, 0, CIRCLE_NUM_POINTS, glm::vec2(0.6, 0.7), 0.2, 1);
// 读取着色器并使用
std::string vshader, fshader;
vshader = "shaders/vshader.glsl";
fshader = "shaders/fshader.glsl";
program = InitShader(vshader.c_str(), fshader.c_str());
glUseProgram(program);
// 创建顶点缓存对象,vbo[2]是因为我们将要使用两个缓存对象
GLuint vbo[2];
/*
* 初始化三角形的数据
*/
glGenVertexArrays(1, &vao[0]);
glBindVertexArray(vao[0]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);
GLuint location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_colors), triangle_colors, GL_STATIC_DRAW);
GLuint cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
/*
* 初始化正方形的数据
*/
glGenVertexArrays(1, &vao[1]);
glBindVertexArray(vao[1]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertices), square_vertices, GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_colors), square_colors, GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
/*
* 初始化线的数据
*/
glGenVertexArrays(1, &vao[2]);
glBindVertexArray(vao[2]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(line_vertices), line_vertices, GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(line_colors), line_colors, GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
// 初始化椭圆
glGenVertexArrays(1, &vao[3]);
glBindVertexArray(vao[3]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(ellipse_vertices), ellipse_vertices, GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(ellipse_colors), ellipse_colors, GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
//初始化圆
glGenVertexArrays(1, &vao[4]);
glBindVertexArray(vao[4]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(circle_vertices), circle_vertices, GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(
location,
2,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(circle_colors), circle_colors, GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(
cLocation,
3,
GL_FLOAT,
GL_FALSE,
sizeof(glm::vec3),
BUFFER_OFFSET(0));
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glBindVertexArray(vao[0]);
glDrawArrays(GL_TRIANGLES, 0, TRIANGLE_NUM_POINTS);
glBindVertexArray(vao[1]);
for (int i = 0; i < SQUARE_NUM; ++i) {
glDrawArrays(GL_TRIANGLE_FAN, (i * 4), 4);
}
glBindVertexArray(vao[2]);
glDrawArrays(GL_LINES, 0, LINE_NUM_POINTS);
// @TODO: 绘制圆
glBindVertexArray(vao[4]);
glDrawArrays(GL_TRIANGLE_FAN, 0, CIRCLE_NUM_POINTS);
// @TODO: 绘制椭圆
glBindVertexArray(vao[3]);
glDrawArrays(GL_TRIANGLE_FAN, 0, ELLIPSE_NUM_POINTS);
glFlush();
}
int main(int argc, char **argv)
{
// 初始化GLFW库
glfwInit();
// 配置GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// 配置窗口属性
GLFWwindow* window = glfwCreateWindow(512, 512, "学号_姓名_实验一", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 调用任何OpenGL的函数之前初始化GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
init();
std::cout << "OpenGL Vendor: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "OpenGL Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "Supported GLSL version is: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
while (!glfwWindowShouldClose(window))
{
display();
// 交换颜色缓冲 以及 检查有没有触发什么事件(比如键盘输入、鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
return 0;
}
设计图形
#include <string>
#include "Angel.h"
const glm::vec3 WHITE(1.0, 1.0, 1.0);
const glm::vec3 BLACK(0.0, 0.0, 0.0);
const glm::vec3 RED(1.0, 0.0, 0.0);
const glm::vec3 GREEN(0.0, 1.0, 0.0);
const glm::vec3 BLUE(0.0, 0.0, 1.0);
const glm::vec3 OTHER_BLUE(0.0, 0.749, 1.0);
const int CIRCLE_NUM_POINTS = 100;
const int ELLIPSE_NUM_POINTS = 100;
const int TRIANGLE_NUM_POINTS = 3;
const int SQUARE_NUM = 6;
const int SQUARE_NUM_POINTS = 4 * SQUARE_NUM;
// 颜色插值函数
glm::vec3 interpolateColors(glm::vec3 color1, glm::vec3 color2, double t) {
return glm::mix(color1, color2, t);
}
// 每当窗口改变大小,GLFW会调用这个函数并填充相应的参数
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
// 根据角度生成颜色
float generateAngleColor(double angle) {
return 1.0 / (2 * M_PI) * angle;
}
// 获得三角形的每个角度
double getTriangleAngle(int point) {
return 2 * M_PI / 3 * point;
}
// 获得正方形的每个角度
double getSquareAngle(int point) {
return M_PI / 4 + (M_PI / 2 * point);
}
// 计算椭圆/圆上的点
glm::vec2 getEllipseVertex(glm::vec2 center, double scale, double verticalScale, double angle) {
glm::vec2 vertex(sin(angle), cos(angle));
vertex *= scale;
vertex.y *= verticalScale;
vertex += center;
return vertex;
}
// 获得椭圆/圆的每个顶点
void generateEllipsePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex, int numPoints, glm::vec2 center, double scale, double verticalScale) {
double angleIncrement = (2 * M_PI) / numPoints;
double currentAngle = M_PI / 2;
for (int i = startVertexIndex; i < startVertexIndex + numPoints; ++i) {
vertices[i] = getEllipseVertex(center, scale, verticalScale, currentAngle);
if (verticalScale == 1.0) {
if (startVertexIndex == 2 * CIRCLE_NUM_POINTS || startVertexIndex == 3 * CIRCLE_NUM_POINTS) {
// 眼珠为黑色
colors[i] = BLACK;
}
else {
// 眼睛采用了渐变色
double t = static_cast<double>(i - startVertexIndex) / numPoints;
colors[i] = interpolateColors(WHITE, OTHER_BLUE, t);
}
}
else {
if (startVertexIndex == 0) {
// 鼻子,变化色
colors[i] = glm::vec3(generateAngleColor(currentAngle), generateAngleColor(currentAngle), 1.0);
}
else {
// 头发,红色逐渐过渡到白色
double t = static_cast<double>(i - startVertexIndex) / numPoints;
colors[i] = interpolateColors(RED, WHITE, t);
}
}
currentAngle += angleIncrement;
}
}
// 获得三角形的每个顶点
void generateTrianglePoints(glm::vec2 scale,
glm::vec2 center,
glm::vec2 vertices[],
glm::vec3 colors[],
int startVertexIndex,
double change_angle) {
for (int i = 0; i < 3; ++i) {
double currentAngle = getTriangleAngle(i) + change_angle;
vertices[startVertexIndex + i] = glm::vec2(sin(currentAngle), cos(currentAngle)) * scale + center;
}
if (startVertexIndex == 3 * TRIANGLE_NUM_POINTS) {
// 嘴巴里面的
colors[startVertexIndex] = WHITE;
colors[startVertexIndex + 1] = WHITE;
colors[startVertexIndex + 2] = WHITE;
}
else {
// 其他均为红色
colors[startVertexIndex] = RED;
colors[startVertexIndex + 1] = RED;
colors[startVertexIndex + 2] = RED;
}
}
// 获得正方形的每个顶点
void generateSquarePoints(glm::vec2 vertices[], glm::vec3 colors[], int squareNumber, int startVertexIndex) {
glm::vec2 scale(0.6, 0.6);
glm::vec2 center(0.0, 0.0);
int vertexIndex = startVertexIndex;
for (int i = 0; i < squareNumber; ++i) {
glm::vec3 currentColor;
for (int j = 0; j < 4; ++j) {
double currentAngle = getSquareAngle(j);
currentColor = WHITE;
vertices[vertexIndex] =
glm::vec2(sin(currentAngle), cos(currentAngle)) * scale +
center;
colors[vertexIndex] = currentColor;
vertexIndex++;
}
}
}
GLuint vao[5], program;
void init() {
// 定义三角形的点
glm::vec2 triangle_vertices[4 * TRIANGLE_NUM_POINTS];
glm::vec3 triangle_colors[4 * TRIANGLE_NUM_POINTS];
// 定义正方形的点
glm::vec2 square_vertices[SQUARE_NUM_POINTS];
glm::vec3 square_colors[SQUARE_NUM_POINTS];
// 定义椭圆的点
glm::vec2 elipse_vertices[3 * ELLIPSE_NUM_POINTS];
glm::vec3 elipse_colors[3 * ELLIPSE_NUM_POINTS];
// 定义圆的点
glm::vec2 circle_vertices[4 * CIRCLE_NUM_POINTS];
glm::vec3 circle_colors[4 * CIRCLE_NUM_POINTS];
// 正方形(整个脸庞)
generateSquarePoints(square_vertices, square_colors, 1, 0);
// 椭圆(鼻子)
glm::vec2 elipse_center1(0.0, 0.0);
generateEllipsePoints(elipse_vertices, elipse_colors, 0, ELLIPSE_NUM_POINTS,
elipse_center1, 0.05, 1.4);
// 椭圆(头发),两个
glm::vec2 elipse_center2(0.18, 0.42);
generateEllipsePoints(elipse_vertices, elipse_colors, ELLIPSE_NUM_POINTS, ELLIPSE_NUM_POINTS,
elipse_center2, 0.13, 0.25);
glm::vec2 elipse_center3(-0.18, 0.42);
generateEllipsePoints(elipse_vertices, elipse_colors, 2 * ELLIPSE_NUM_POINTS, ELLIPSE_NUM_POINTS,
elipse_center3, 0.13, 0.25);
// 圆(眼睛)
glm::vec2 circle_center1(-0.15, 0.15);
generateEllipsePoints(circle_vertices, circle_colors, 0, CIRCLE_NUM_POINTS, circle_center1, 0.08, 1.0);
glm::vec2 circle_center2(0.15, 0.15);
generateEllipsePoints(circle_vertices, circle_colors, CIRCLE_NUM_POINTS, CIRCLE_NUM_POINTS, circle_center2, 0.08, 1.0);
// 圆(眼珠)
generateEllipsePoints(circle_vertices, circle_colors, 2 * CIRCLE_NUM_POINTS, CIRCLE_NUM_POINTS, circle_center1, 0.03, 1.0);
generateEllipsePoints(circle_vertices, circle_colors, 3 * CIRCLE_NUM_POINTS, CIRCLE_NUM_POINTS, circle_center2, 0.03, 1.0);
// 三角形(耳朵,嘴巴)
glm::vec2 traTriangle_scale1(0.1, 0.1);
glm::vec2 traTriangle_scale2(0.16, 0.16);
glm::vec2 traTriangle_scale3(0.09, 0.09);
glm::vec2 traTriangle_center1(-0.48, 0.0);
glm::vec2 traTriangle_center2(0.48, 0.0);
glm::vec2 traTriangle_center3(0.0, -0.2);
generateTrianglePoints(traTriangle_scale1, traTriangle_center1, triangle_vertices, triangle_colors, 0, 3 * M_PI / 2);
generateTrianglePoints(traTriangle_scale1, traTriangle_center2, triangle_vertices, triangle_colors, TRIANGLE_NUM_POINTS, M_PI / 2);
generateTrianglePoints(traTriangle_scale2, traTriangle_center3, triangle_vertices, triangle_colors, 2 * TRIANGLE_NUM_POINTS, M_PI);
generateTrianglePoints(traTriangle_scale3, traTriangle_center3, triangle_vertices, triangle_colors, 3 * TRIANGLE_NUM_POINTS, M_PI);
// 读取着色器并使用
std::string vshader, fshader;
vshader = "shaders/vshader.glsl";
fshader = "shaders/fshader.glsl";
program = InitShader(vshader.c_str(), fshader.c_str());
glUseProgram(program);
// 创建顶点缓存对象,vbo[2]是因为我们将要使用两个缓存对象
GLuint vbo[2];
/*
* 初始化正方形的数据
*/
glGenVertexArrays(1, &vao[1]);
glBindVertexArray(vao[1]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertices), square_vertices,
GL_STATIC_DRAW);
GLuint location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_colors), square_colors,
GL_STATIC_DRAW);
GLuint cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(cLocation, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3),
BUFFER_OFFSET(0));
/*
* 初始化三角形的数据
*/
glGenVertexArrays(1, &vao[0]);
glBindVertexArray(vao[0]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices,
GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_colors), triangle_colors,
GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(cLocation, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3),
BUFFER_OFFSET(0));
/*
* 初始化椭圆的数据
*/
glGenVertexArrays(1, &vao[3]);
glBindVertexArray(vao[3]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(elipse_vertices), elipse_vertices,
GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(elipse_colors), elipse_colors,
GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(cLocation, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3),
BUFFER_OFFSET(0));
/*
* 初始化圆的数据
*/
glGenVertexArrays(1, &vao[4]);
glBindVertexArray(vao[4]);
glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(circle_vertices), circle_vertices,
GL_STATIC_DRAW);
location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2),
BUFFER_OFFSET(0));
glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(circle_colors), circle_colors,
GL_STATIC_DRAW);
cLocation = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(cLocation);
glVertexAttribPointer(cLocation, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3),
BUFFER_OFFSET(0));
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
// 绘制正方形
// 得先画正方形,否则有一个三角形会被遮住
glBindVertexArray(vao[1]);
for (int i = 0; i < SQUARE_NUM; ++i) {
glDrawArrays(GL_TRIANGLE_FAN, (i * 4), 4);
}
// 绘制三角形
// 红色的(耳朵,嘴巴)
glBindVertexArray(vao[0]);
glDrawArrays(GL_TRIANGLES, 0, TRIANGLE_NUM_POINTS);
glDrawArrays(GL_TRIANGLES, TRIANGLE_NUM_POINTS, TRIANGLE_NUM_POINTS);
glDrawArrays(GL_TRIANGLES, 2 * TRIANGLE_NUM_POINTS, TRIANGLE_NUM_POINTS);
// 白色的(嘴巴里面)
glDrawArrays(GL_TRIANGLES, 3 * TRIANGLE_NUM_POINTS, TRIANGLE_NUM_POINTS);
// 绘制圆(眼睛)
glBindVertexArray(vao[4]);
glDrawArrays(GL_TRIANGLE_FAN, 0, CIRCLE_NUM_POINTS);
glBindVertexArray(vao[4]);
glDrawArrays(GL_TRIANGLE_FAN, CIRCLE_NUM_POINTS, CIRCLE_NUM_POINTS);
glBindVertexArray(vao[4]);
// 绘制圆(眼珠)
glDrawArrays(GL_TRIANGLE_FAN, 2 * CIRCLE_NUM_POINTS, CIRCLE_NUM_POINTS);
glBindVertexArray(vao[4]);
glDrawArrays(GL_TRIANGLE_FAN, 3 * CIRCLE_NUM_POINTS, CIRCLE_NUM_POINTS);
// 绘制椭圆(鼻子)
glBindVertexArray(vao[3]);
glDrawArrays(GL_TRIANGLE_FAN, 0, ELLIPSE_NUM_POINTS);
// 绘制椭圆(头发),两个
glBindVertexArray(vao[3]);
glDrawArrays(GL_TRIANGLE_FAN, ELLIPSE_NUM_POINTS, ELLIPSE_NUM_POINTS);
glBindVertexArray(vao[3]);
glDrawArrays(GL_TRIANGLE_FAN, 2 * ELLIPSE_NUM_POINTS, ELLIPSE_NUM_POINTS);
glFlush();
}
int main(int argc, char** argv) {
// 初始化GLFW库
glfwInit();
// 配置GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// 配置窗口属性
GLFWwindow* window = glfwCreateWindow(512, 512, "学号_姓名_实验一", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 调用任何OpenGL的函数之前初始化GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
init();
std::cout << "OpenGL Vendor: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "OpenGL Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "Supported GLSL version is: "
<< glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
while (!glfwWindowShouldClose(window)) {
display();
// 交换颜色缓冲以及检查有没有触发什么事件(比如键盘输入、鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
return 0;
}
标签:glm,OpenGL,图形学,colors,NUM,vec2,深圳大学,GL,POINTS
From: https://blog.csdn.net/qq_73179413/article/details/145147701