实现五角星的放大缩小和旋转以及模拟碰撞
主代码 main.cpp
#include<iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include<cmath>
#include <math.h>
#include <vector>
#include<shader.h>
#include<object2d.h>
#include<glm-0.9.9.8/glm/glm.hpp>
#include<glm-0.9.9.8/glm/gtc/matrix_transform.hpp>
#include<glm-0.9.9.8/glm/gtc/type_ptr.hpp>
#define pi 3.14159265
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
float ang2rad(float ang) {
return (ang * pi) / 180;
}
float findBiggerRadius(float smallR) {
float a, b, c, x1, x2, d;
float num1 = sin(ang2rad(36)) / sin(ang2rad(126));
a = (1 - (pow(num1, 2)));
b = (2 * num1 * smallR * cos(ang2rad(126)));
c = -(smallR * smallR);
//scanf("%f %f %f",&a,&b,&c);
if (a != 0)
{
d = sqrt(b * b - 4 * a * c);
x1 = (-b + d) / (2 * a);
x2 = (-b - d) / (2 * a);
if (x1 < x2)
return x2;
else
return x1;
}
return -1;
}
float scale_value = 1.0f;
float route_value = 0.0f;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)//按下esc退出程序
{
glfwSetWindowShouldClose(window, GL_TRUE);
}
else if (key == GLFW_KEY_S && scale_value >= 0.1)
{
scale_value = scale_value -0.05;
}
else if (key == GLFW_KEY_W && scale_value <= 0.9)
{
scale_value = scale_value + 0.05;
}
else if (key == GLFW_KEY_Q)
{
route_value = route_value + 5.0f;
}
else if (key == GLFW_KEY_E)
{
route_value = route_value - 5.0f;
}
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//将主版本号(Major)和次版本号(Minor)都设为3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//告诉GLFW我们使用的是核心模式(Core-profile)
GLFWwindow* window = glfwCreateWindow(800, 800, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))//我们给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数。
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
Shader ourShader("shader/vertexShader.glsl", "shader/fragmentShader.glsl");
Shader movStar("shader/vertexShader_move.glsl", "shader/fragmentShader.glsl");
float v_center = 0.0f;
float radius_small = 0.3f;
float radius_big = findBiggerRadius(radius_small);
float v[35];
float degree = 54.0f;
int i = 0;
while (i < 15) {
v[i++] = v_center + radius_small * cos(ang2rad(degree));
v[i++] = v_center + radius_small * sin(ang2rad(degree));
v[i++] = 1.0f;
degree += 72.0f;
}
degree = 18.0f;
while (i < 30) {
v[i++] = v_center + radius_big * cos(ang2rad(degree));
v[i++] = v_center + radius_big * sin(ang2rad(degree));
v[i++] = 1.0f;
degree += 72.0f;
}
v[i++] = v_center;
v[i++] = v_center;
v[i++] = 1.0f;
unsigned int indices[] = {
0, 6, 10,
6, 1, 10,
1, 7, 10,
2, 7, 10,
2, 8, 10,
3, 8, 10,
3, 9, 10,
4, 9, 10,
4, 5, 10,
0, 5, 10
};
unsigned int indices2[] = {
0, 1, 3,
0, 1, 2
};
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
unsigned int VBO[2], VAO[2], EBO[2];
glGenVertexArrays(2, VAO);
glGenBuffers(2, VBO);
glGenBuffers(2, EBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//VAO解绑前不能解绑EBO,如:glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//VAO解绑前不能解绑EBO,如:glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
int flag = -1;
float translate1 = 0.0f;
float translate2 = 0.0f;
while (!glfwWindowShouldClose(window))//我们需要在程序中添加一个while循环,我们可以把它称之为渲染循环(Render Loop),它能在我们让GLFW退出前一直保持运行
{
// 输入
processInput(window);
//glm
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::scale(trans, glm::vec3(scale_value, scale_value, scale_value));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
trans = glm::rotate(trans, glm::radians(route_value), glm::vec3(0.0f, 0.0f, 1.0f));
glfwSetKeyCallback(window, key_callback);
//渲染指令QAQ
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ourShader.use();
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
glViewport(0, 0, 800, 800);
glBindVertexArray(VAO[0]);
glDrawElements(GL_TRIANGLES, 30, GL_UNSIGNED_INT, 0);
movStar.use();
glm::mat4 trans_mov = glm::mat4(1.0f);
//trans_mov = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
trans_mov = glm::translate(trans_mov, glm::vec3(translate1, translate2, 0.0f));
trans_mov = glm::translate(trans_mov, glm::vec3(0.8f, 0.8f, 0.0f));
trans_mov = glm::rotate(trans_mov, (float)glfwGetTime()*10, glm::vec3(0.0f, 0.0f, 1.0f));
unsigned int transformLoc_mov = glGetUniformLocation(movStar.ID, "transform_mov");
glBindVertexArray(VAO[1]);
glUniformMatrix4fv(transformLoc_mov, 1, GL_FALSE, glm::value_ptr(trans_mov));
glDrawElements(GL_TRIANGLES, 30, GL_UNSIGNED_INT, 0);
//检查并调用事件,交换缓冲
glfwSwapBuffers(window);
glfwPollEvents();
if (translate1 > 0.1f) {//
flag = 1; // right
}
if (translate1 < -1.7f) {
flag = 2; //left
}
if (translate2 > 0.1f) {
flag = 3; //up
}
if (translate2 < -1.7f) {
flag = 4;//down
}
if (translate2>-1.2f&&translate2 < -0.5f && (translate1<-0.2f)&& (translate1>-1.0f)) {
flag = -1;
}
if (flag == -1) {//default
translate1 = translate1 - 0.0001f;
translate2 = translate2 - 0.002f;
}
if (flag == 1) {//right
translate1 = translate1 - 0.002f;
translate2 = translate2 + 0.0005f;
}
if(flag ==2) {//left
translate1 = translate1 + 0.002f;
translate2 = translate2 - 0.0001f;
}
if (flag == 3) {
translate2 = translate2 - 0.001f;
translate1 = translate1 - 0.0005f;
}
if (flag == 4) {
translate2 = translate2 + 0.0005f;
translate1 = translate1 - 0.0007f;
}
}
glfwTerminate();
return 0;
}
着色器构造代码 shader.h
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h> // 包含glad来获取所有的必须OpenGL头文件
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
Shader(const char* vertexPath, const char* fragmentPath) {
// 1. 从文件路径中获取顶点/片段着色器
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// 保证ifstream对象可以抛出异常:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// 打开文件
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// 读取文件的缓冲内容到数据流中
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭文件处理器
vShaderFile.close();
fShaderFile.close();
// 转换数据流到string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. 编译着色器
unsigned int vertex, fragment;
int success;
char infoLog[512];
// 顶点着色器
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// 打印编译错误(如果有的话)
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 片段着色器也类似
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
// 打印编译错误(如果有的话)
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 着色器程序
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
// 打印连接错误(如果有的话)
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void use(){
glUseProgram(ID);
}
void setBool(const std::string& name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void setInt(const std::string& name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void setFloat(const std::string& name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
};
#endif
顶点坐标着色器代码1 vertexShader.glsl
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0
out vec4 vertexColor; // 为片段着色器指定一个颜色输出
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(0.4* aPos, 1.0f);
//gl_Position = vec4(aPos, 1.0f);
vertexColor = vec4(1.0, 0.0, 0.0, 1.0);
}
顶点坐标着色器2 vertexShader_move.glsl
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0
out vec4 vertexColor; // 为片段着色器指定一个颜色输出
uniform mat4 transform_mov;
void main()
{
gl_Position = transform_mov * vec4(0.1f *aPos, 1.0f);
//gl_Position = vec4(aPos, 1.0f);
vertexColor = vec4(1.0, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色
}
片段着色器1 fragmentShader.glsl
#version 330 core
out vec4 FragColor;
in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)
void main()
{
FragColor = vertexColor;
}