参考文章
配置OpenGL环境看上一篇文章
效果图:
main.cpp:
#include "Dependencies/glew/glew.h"
#include "Dependencies/GLFW/glfw3.h"#include "Dependencies/glm/glm.hpp"
#include "Dependencies/glm/gtc/matrix_transform.hpp"#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>GLint programID;unsigned int VBO, VAO, EBO;const unsigned int SCR_WIDTH = 1200;
const unsigned int SCR_HEIGHT = 1200;const GLfloat PI = 3.14159265358979323846f;//将球横纵划分成50X50的网格
const int Y_SEGMENTS = 50;
const int X_SEGMENTS = 50;void get_OpenGL_info() {// OpenGL informationconst GLubyte* name = glGetString(GL_VENDOR);const GLubyte* renderer = glGetString(GL_RENDERER);const GLubyte* glversion = glGetString(GL_VERSION);std::cout << "OpenGL company: " << name << std::endl;std::cout << "Renderer name: " << renderer << std::endl;std::cout << "OpenGL version: " << glversion << std::endl;
}bool checkStatus(GLuint objectID,PFNGLGETSHADERIVPROC objectPropertyGetterFunc,PFNGLGETSHADERINFOLOGPROC getInfoLogFunc,GLenum statusType)
{GLint status;objectPropertyGetterFunc(objectID, statusType, &status);if (status != GL_TRUE){GLint infoLogLength;objectPropertyGetterFunc(objectID, GL_INFO_LOG_LENGTH, &infoLogLength);GLchar* buffer = new GLchar[infoLogLength];GLsizei bufferSize;getInfoLogFunc(objectID, infoLogLength, &bufferSize, buffer);std::cout << buffer << std::endl;delete[] buffer;return false;}return true;
}bool checkShaderStatus(GLuint shaderID) {return checkStatus(shaderID, glGetShaderiv, glGetShaderInfoLog, GL_COMPILE_STATUS);
}bool checkProgramStatus(GLuint programID) {return checkStatus(programID, glGetProgramiv, glGetProgramInfoLog, GL_LINK_STATUS);
}std::string readShaderCode(const char* fileName) {std::ifstream meInput(fileName);if (!meInput.good()) {std::cout << "File failed to load ... " << fileName << std::endl;exit(1);}return std::string(std::istreambuf_iterator<char>(meInput),std::istreambuf_iterator<char>());
}void installShaders() {GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);const GLchar* adapter[1];//adapter[0] = vertexShaderCode;std::string temp = readShaderCode("VertexShaderCode.glsl");adapter[0] = temp.c_str();glShaderSource(vertexShaderID, 1, adapter, 0);//adapter[0] = fragmentShaderCode;temp = readShaderCode("FragmentShaderCode.glsl");adapter[0] = temp.c_str();glShaderSource(fragmentShaderID, 1, adapter, 0);glCompileShader(vertexShaderID);glCompileShader(fragmentShaderID);if (!checkShaderStatus(vertexShaderID) || !checkShaderStatus(fragmentShaderID))return;programID = glCreateProgram();glAttachShader(programID, vertexShaderID);glAttachShader(programID, fragmentShaderID);glLinkProgram(programID);if (!checkProgramStatus(programID))return;glDeleteShader(vertexShaderID);glDeleteShader(fragmentShaderID);glUseProgram(programID);}void sendDataToOpenGL() {// TODO:// create 2D objects and 3D objects and/or lines (points) here and bind to VAOs & VBOsstd::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);}}// 生成球的Indicesfor (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);}}glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // because the vertex data is tightly packed we can also specify 0 as the vertex attribute's stride to let OpenGL figure it outglEnableVertexAttribArray(0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);}void paintGL(void) {// always run// TODO:// render your objects and control the transformation hereglClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glm::mat4 projection = glm::mat4(1.0f);glm::mat4 model = glm::mat4(1.0f);glm::mat4 view = glm::mat4(1.0f);glUniformMatrix4fv(glGetUniformLocation(programID, "projection"), 1, GL_FALSE, &projection[0][0]);glUniformMatrix4fv(glGetUniformLocation(programID, "view"), 1, GL_FALSE, &view[0][0]);glUniformMatrix4fv(glGetUniformLocation(programID, "model"), 1, GL_FALSE, &model[0][0]);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);}void framebuffer_size_callback(GLFWwindow* window, int width, int height) {glViewport(0, 0, width, height);
}void initializedGL(void) {// run only once// TODO:sendDataToOpenGL();installShaders();glEnable(GL_DEPTH_TEST);
}int main(int argc, char* argv[]) {GLFWwindow* window;/* Initialize the glfw */if (!glfwInit()) {std::cout << "Failed to initialize GLFW" << std::endl;return -1;}/* glfw: configure; necessary for MAC */glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif/* do not allow resizing */glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);/* Create a windowed mode window and its OpenGL context */window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Assignment 1", NULL, NULL);if (!window) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}/* Make the window's context current */glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);/* Initialize the glew */if (GLEW_OK != glewInit()) {std::cout << "Failed to initialize GLEW" << std::endl;return -1;}get_OpenGL_info();initializedGL();/* Loop until the user closes the window */while (!glfwWindowShouldClose(window)) {/* Render here */paintGL();/* Swap front and back buffers */glfwSwapBuffers(window);/* Poll for and process events */glfwPollEvents();}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);
}
想画的更圆可以通过增大全局变量Y_SEGMENTS和X_SEGMENTS
下面是100时的效果
要给球体上颜色的话,每次生成顶点时要压入三个颜色的比例值,同时在顶点着色器中加入颜色输入值,下面是修改部分:
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);//压入颜色sphereVertices.push_back(sin(xPos) / 2 + 0.5);sphereVertices.push_back(sin(yPos) / 2 + 0.5);sphereVertices.push_back(sin(zPos) / 2 + 0.5);}}
同时将颜色传入顶点着色器中,注意偏移值要改成6
glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0);//新增两行glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (char*)(3 * sizeof(float))); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);
绘线模式去除
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);
顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;out vec3 ourColor;void main()
{gl_Position = vec4(aPos, 1.0);ourColor = aColor ;
}
片段着色器:
#version 330 coreout vec4 FragColor;in vec3 ourColor;void main()
{FragColor = vec4(ourColor,1.0);
}
效果图:
工程文件