【OpenGL】平面几何变换实现五角星的放大缩小和旋转以及模拟碰撞

实现五角星的放大缩小和旋转以及模拟碰撞

主代码 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;
}

运行效果

在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

a9c93f2300

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

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

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

打赏作者

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

抵扣说明:

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

余额充值