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函数来绘制球体。