OpenGL画球面(6)

1 画球,先要把球面按照经纬线,分成N等分;在每两条经纬线包着的区域就相当于是一个四边形,这个四边形是两个三角形拼成的;

2 画球要计算球面上顶点的坐标,我们暂时不做球面贴图,不考虑纹理坐标

3本博客根据华科万琳老师的讲义进行编写;如有冒犯,请及时评论联系;

3.1如何计算球面上某一个点P的坐标:

 

 

 

 

 

 

 注意看β的位置:不要被俯视图的那条灰色的线迷惑;

 

 上边你已经知道P的X,Y, Z坐标要如何计算了,那关键是找到α和β,下边看如何找到某一个点的的这个两个角度

 

顶点的坐标的计算(R=1):

3.2 通过三角形图元构造球体面片

 

3.3下边要开始构造顶点索引:顶点索引的代码会在后边统一贴出

 

 

 

 

 

 

 3.4 关于背面剔除

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);线框模式

glEnable(GL_CULL_FACE);//背面剔除
glCullFace(GL_BACK);

背面剔除效果展示:

                                                         

 

如果不剔除背面会怎么样:

                                                 

 

 好了,到此圆球画完了

代码来源于万琳老师课件:支持老师官方地址观看:计算机图形学_华中科技大学_中国大学MOOC(慕课) (icourse163.org)

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <shader.h>  这个头文件你下载了learnopengl的源码里边就有了
#include <iostream>
#include <math.h>
#include <vector>
const unsigned int screen_width = 780;
const unsigned int screen_height = 780;

const GLfloat  PI = 3.14159265358979323846f;

//将球横纵划分成X*Y的网格
const int Y_SEGMENTS = 10;
const int X_SEGMENTS = 10;


int main()
{
    // 初始化GLFW
    glfwInit();                                                     // 初始化GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);                  // OpenGL版本为3.3,主次版本号均设为3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用核心模式(无需向后兼容性)
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 如果使用的是Mac OS X系统,需加上这行
    glfwWindowHint(GLFW_RESIZABLE, 0);                            // 不可改变窗口大小

                                                                    // 创建窗口(宽、高、窗口名称)
    auto window = glfwCreateWindow(screen_width, screen_height, "Sphere", nullptr, nullptr);
    if (window == nullptr) {                                        // 如果窗口创建失败,输出Failed to Create OpenGL Context
        std::cout << "Failed to Create OpenGL Context" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);                                 // 将窗口的上下文设置为当前线程的主上下文

                                                                    // 初始化GLAD,加载OpenGL函数指针地址的函数
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
    glViewport(0, 0, screen_width, screen_height);




    Shader shader("res/shader/task3.vs", "res/shader/task3.fs");//加载着色器

    std::vector<float> sphereVertices;
    std::vector<int> sphereIndices;


    // 生成球的顶点
    for (int y = 0; y <= Y_SEGMENTS; y++)
    {
        for (int x = 0; x <= X_SEGMENTS; x++)
        {
            float xSegment = (float)x / (float)X_SEGMENTS;
            float ySegment = (float)y / (float)Y_SEGMENTS;
            float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
            float yPos = std::cos(ySegment * PI);
            float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);


            sphereVertices.push_back(xPos);
            sphereVertices.push_back(yPos);
            sphereVertices.push_back(zPos);
        }
    }

    // 生成球的;三角形面索引
    for (int i = 0; i < Y_SEGMENTS; i++)
    {
        for (int j = 0; j < X_SEGMENTS; j++)
        {

            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);

            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j + 1);
        }
    }


    //
    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    //生成并绑定球体的VAO和VBO
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 将顶点数据绑定至当前默认的缓冲中
    glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);

    GLuint element_buffer_object; //EBO
    glGenBuffers(1, &element_buffer_object);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_object);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 解绑VAO和VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);


    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
        // 清空颜色缓冲
        glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        shader.use();
        //绘制球
        //开启面剔除(只需要展示一个面,否则会有重合)
        //glEnable(GL_CULL_FACE);
        //glCullFace(GL_BACK);
        glBindVertexArray(VAO);
        //使用线框模式绘制
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glDrawElements(GL_TRIANGLES, X_SEGMENTS*Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);
        //点阵模式绘制
        //glPointSize(5);
        //glDrawElements(GL_POINTS, X_SEGMENTS*Y_SEGMENTS*6, GL_UNSIGNED_INT, 0);
        //交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 删除VAO和VBO,EBO
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &element_buffer_object);

    // 清理所有的资源并正确退出程序
    glfwTerminate();
    return 0;
}
#version 330 core
layout (location = 0) in vec3 aPos;


void main()
{
    gl_Position =vec4(aPos, 1.0);
}
---------------------------------------
#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0,0.635,0.345,1.0);
}

 

posted on 2022-05-20 00:21  邗影  阅读(1221)  评论(0编辑  收藏  举报

导航