OpenGL画球面(6)
作者:互联网
1 画球,先要把球面按照经纬线,分成N等分;在每两条经纬线包着的区域就相当于是一个四边形,这个四边形是两个三角形拼成的;
2 画球要计算球面上顶点的坐标,我们暂时不做球面贴图,不考虑纹理坐标
3本博客根据华科万琳老师的讲义进行编写;如有侵权,请及时评论联系;
3.1如何计算球面上某一个点P的坐标:
注意看β的位置:
上边你已经知道P的X,Y, Z左边要如何计算了,那关键是找到α和β,下边看如何找到某一个点的的这个两个角度
“这一部分就是生成顶点的代码实现,Y_SEGMENTS 和 X_SEGMENTS 表 示将α 和β 分割了多少份,y 和 x 表示分别是第几份,以此进行遍历, xSegment*2.0f*PI 即β 角,ySegment*PI 即α 角。”--引用自实验
“需要注意的是,在横向分割时,n=0 和 n= X_SEGMENTS 是位置相同的点, 如果后期需要加载纹理则不能随意将之舍去,所以顶点总数实际上是 (X_SEGMENTS + 1)* (Y_SEGMENTS+1)”--引用自万琳老师实验
3.2
由于 opengl 中是以三角形为基本图元进行绘制的,所以在我们得到了球面 的顶点数组后,我们需要构造成基本的三角形图元。
3.3下边要开始构造顶点索引:顶点索引的代码会在后边统一贴出
3.4 关于背面剔除
“ 由于 opengl 中默认的绘 制方式为填充模式,所以我们需要改填充模式为线框模式,这样可以更好的检 查绘制结果”
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);线框模式
“ 由于 opengl 中绘制时会同时绘制正面和背面,并且我们开启了线框模式后, 并不能通过深度测试将背面遮挡住,所以我们需要开启面剔除。来将背面剔除, 面剔除主要是剔除顶点绕法为顺时针的面”
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
背面剔除效果展示:
如果不剔除背面会怎么样:
好了,到此圆球画完了
代码来源于万琳老师课件:
#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); }
标签:GL,OpenGL,int,球面,SEGMENTS,GLFW,顶点,include 来源: https://www.cnblogs.com/8335IT/p/16290888.html