opengl3 画圆球

时间: 2023-11-08 16:51:54 浏览: 41
在OpenGL中,可以通过绘制一组三角形来近似绘制一个圆球。以下是一种实现方法: 1. 首先,定义一个球体的半径r和分割数n(用于控制球体的精度)。 2. 生成球体上每个顶点的坐标。可以使用球面坐标系来计算每个顶点的位置。球面坐标系包括两个角度:θ(纬度)和φ(经度)。对于每个纬度和经度,可以计算出对应的x、y、z坐标,从而生成球体上的所有顶点。 3. 生成球体上每个三角形的顶点索引。可以从球体的顶部(北极)开始,逐层向下生成三角形。每层的三角形数为2n,最后一层只有一个三角形。根据顶点的索引,可以将这些三角形绘制出来。 以下是使用OpenGL3.3绘制圆球的代码: ```c++ #include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <iostream> #include <vector> //定义球体的半径和分割数 float radius = 1.0f; int segments = 50; int main() { //初始化GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return -1; } //创建窗口 GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Sphere", nullptr, nullptr); if (!window) { std::cerr << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } //将窗口设置为当前上下文 glfwMakeContextCurrent(window); //初始化GLEW if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW" << std::endl; glfwTerminate(); return -1; } //定义球体顶点的坐标和法向量 std::vector<glm::vec3> vertices; std::vector<glm::vec3> normals; for (int j = 0; j <= segments; j++) { float theta = j * glm::pi<float>() / segments; float sinTheta = sin(theta); float cosTheta = cos(theta); for (int i = 0; i <= segments; i++) { float phi = i * 2 * glm::pi<float>() / segments; float sinPhi = sin(phi); float cosPhi = cos(phi); float x = cosPhi * sinTheta; float y = cosTheta; float z = sinPhi * sinTheta; vertices.push_back(glm::vec3(x, y, z) * radius); normals.push_back(glm::vec3(x, y, z)); } } //定义球体顶点的索引 std::vector<unsigned int> indices; for (int j = 0; j < segments; j++) { for (int i = 0; i < segments; i++) { unsigned int index1 = j * (segments + 1) + i; unsigned int index2 = j * (segments + 1) + i + 1; unsigned int index3 = (j + 1) * (segments + 1) + i; unsigned int index4 = (j + 1) * (segments + 1) + i + 1; indices.push_back(index1); indices.push_back(index3); indices.push_back(index2); indices.push_back(index2); indices.push_back(index3); indices.push_back(index4); } } //创建VBO和VAO GLuint vbo, vao, ebo; glGenBuffers(1, &vbo); glGenVertexArrays(1, &vao); glGenBuffers(1, &ebo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void*)0); //创建着色器程序 GLuint shaderProgram = glCreateProgram(); //编译顶点着色器 const char* vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "layout (location = 1) in vec3 aNormal;\n" "out vec3 Normal;\n" "out vec3 FragPos;\n" "uniform mat4 model;\n" "uniform mat4 view;\n" "uniform mat4 projection;\n" "void main()\n" "{\n" " gl_Position = projection * view * model * vec4(aPos, 1.0);\n" " Normal = mat3(transpose(inverse(model))) * aNormal;\n" " FragPos = vec3(model * vec4(aPos, 1.0));\n" "}\0"; GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); glCompileShader(vertexShader); //检查顶点着色器是否编译成功 int success; char infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); std::cerr << "Failed to compile vertex shader: " << infoLog << std::endl; return -1; } //编译片段着色器 const char* fragmentShaderSource = "#version 330 core\n" "in vec3 Normal;\n" "in vec3 FragPos;\n" "out vec4 FragColor;\n" "uniform vec3 lightPos;\n" "uniform vec3 viewPos;\n" "uniform vec3 objectColor;\n" "uniform vec3 lightColor;\n" "void main()\n" "{\n" " vec3 ambient = 0.2 * lightColor;\n" " vec3 norm = normalize(Normal);\n" " vec3 lightDir = normalize(lightPos - FragPos);\n" " float diff = max(dot(norm, lightDir), 0.0);\n" " vec3 diffuse = diff * lightColor;\n" " vec3 viewDir = normalize(viewPos - FragPos);\n" " vec3 reflectDir = reflect(-lightDir, norm);\n" " float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);\n" " vec3 specular = spec * lightColor;\n" " vec3 result = (ambient + diffuse + specular) * objectColor;\n" " FragColor = vec4(result, 1.0);\n" "}\0"; GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader); //检查片段着色器是否编译成功 glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog); std::cerr << "Failed to compile fragment shader: " << infoLog << std::endl; return -1; } //将着色器链接到着色器程序中 glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); //检查着色器程序是否链接成功 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); std::cerr << "Failed to link shader program: " << infoLog << std::endl; return -1; } //删除着色器对象 glDeleteShader(vertexShader); glDeleteShader(fragmentShader); //设置光源和视点位置 glm::vec3 lightPos(0.0f, 1.0f, 0.0f); glm::vec3 viewPos(0.0f, 0.0f, 3.0f); //启用深度测试 glEnable(GL_DEPTH_TEST); //设置清除颜色和深度缓冲的值 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //设置模型矩阵、视图矩阵和投影矩阵 glm::mat4 model = glm::mat4(1.0f); glm::mat4 view = glm::lookAt(viewPos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); //设置着色器程序中的uniform变量 glUseProgram(shaderProgram); glUniform3fv(glGetUniformLocation(shaderProgram, "lightPos"), 1, glm::value_ptr(lightPos)); glUniform3fv(glGetUniformLocation(shaderProgram, "viewPos"), 1, glm::value_ptr(viewPos)); glUniform3fv(glGetUniformLocation(shaderProgram, "objectColor"), 1, glm::value_ptr(glm::vec3(1.0f, 0.5f, 0.31f))); glUniform3fv(glGetUniformLocation(shaderProgram, "lightColor"), 1, glm::value_ptr(glm::vec3(1.0f, 1.0f, 1.0f))); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); //绘制球体 glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); //交换缓冲区并查询事件 glfwSwapBuffers(window); glfwPollEvents(); //释放资源 glDeleteProgram(shaderProgram); glDeleteBuffers(1, &vbo); glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &ebo); //终止GLFW glfwTerminate(); return 0; } ``` 该代码中使用了glm库来进行矩阵和向量的计算。顶点着色器主要负责将模型空间中的顶点坐标转换为剪裁空间中的坐标,并计算出每个顶点的法向量。片段着色器主要负责计算每个片段的颜色,包括环境光、漫反射和镜面反射。在主函数中,首先生成球体的顶点坐标和法向量,然后使用VBO和VAO来存储和绑定这些数据。接着创建着色器程序,并将uniform变量的值传递给着色器。最后,使用glDrawElements函数来绘制球体。

相关推荐

最新推荐

recommend-type

用OpenGL画哆啦A梦.docx

用OpenGL画哆啦A梦,上下左右键控制整体移动,点击右键也可控制整体移动,哆啦A梦的铃铛能够自动旋转,手可以放大缩小,文档中包含源码及注释,打开codeblocks运行即可。
recommend-type

3d照相机成像原理视景体详解

本资料详细介绍了3d绘图中的照相机模型以及相关算法,并介绍了透视成像过程中的基本概念和投影算法,通过学习本书内容可以了解到3d渲染技术成像原理对学习图形学编程有很好的帮助作用
recommend-type

利用OpenGL绘制一个简单场景:比如球体、正方体

利用OpenGL绘制一个简单场景:比如球体、正方体;加入灯光;实现交互操作:平移、缩放、旋转
recommend-type

Android_3D_OpenGL ES 基础教程

Android_3D_OpenGL ES 基础教程(中文版),从3D相关的基本概念讲起,也是很好的入门资料,需要的同仁拿去
recommend-type

d3d vs openGL

这个PPT主要介绍d3d与openGL的区别与使用,基于用户已经了解d3d,考虑使用OpenGL或d3d.
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

list根据id查询pid 然后依次获取到所有的子节点数据

可以使用递归的方式来实现根据id查询pid并获取所有子节点数据。具体实现可以参考以下代码: ``` def get_children_nodes(nodes, parent_id): children = [] for node in nodes: if node['pid'] == parent_id: node['children'] = get_children_nodes(nodes, node['id']) children.append(node) return children # 测试数
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。