效果如图
准备第三方库 glew、freeglut、glm
代码包括主程序源文件mainApp.cpp、顶点着色器shader.vs、片元着色器shader.fs
mainApp.cpp如下
#include <stdio.h> #include <string.h> #include <iostream> #include <fstream> #include <sstream> #include <GL/glew.h> #include <GL/freeglut.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> using namespace std; using namespace glm; //shader文件 const char* vsShaderName = "shader.vs";//顶点着色器 const char* fsShaderName = "shader.fs";//片元着色器 GLuint VBO;//顶点缓冲对象 GLuint IBO;//索引缓冲对象 static GLfloat *vertices;//顶点数组 static unsigned int *indices; //索引数组 GLuint ShaderProgram; GLuint MatrixID; int windowWidth = 800; int windowHeight = 800; //球体参数 float radius=5.0f;//半径 int longPart=19;//经线数 int latPart=18;//纬线数 int verticeNum = longPart * latPart + 2 * longPart; //相机参数 glm::mat4 ViewMatrix;//视图矩阵 glm::mat4 ProjectionMatrix; //投影矩阵 glm::mat4 MVP;//模型视图矩阵 glm::mat4 ModelMatrix;//模型矩阵 glm::vec3 position = glm::vec3(5, 5, 5); //相机位置 float horizontalAngle = 3.14f; float verticalAngle = 0.0f; float initialFoV = 45.0f; //相机视场角 float speed = 0.05f; //平移速度 float mouseSpeed = 0.05f; int mouseX, mouseY;//鼠标位置 窗口坐标 // 传递键盘事件 static void SpecialKeyboardCB(int Key, int x, int y) { glm::vec3 direction( cos(verticalAngle) * sin(horizontalAngle), sin(verticalAngle), cos(verticalAngle) * cos(horizontalAngle) ); glm::vec3 right = glm::vec3( sin(horizontalAngle - 3.14f / 2.0f), 0, cos(horizontalAngle - 3.14f / 2.0f) ); glm::vec3 up = glm::cross(right, direction); switch (Key) { case GLUT_KEY_UP: position += direction * speed; fprintf(stderr, "up key "); break; case GLUT_KEY_RIGHT: position += right * speed; fprintf(stderr, "right key "); break; case GLUT_KEY_DOWN: position -= direction * speed; fprintf(stderr, "down key "); break; case GLUT_KEY_LEFT: position -= right * speed; fprintf(stderr, "left key "); break; case GLUT_KEY_F4: exit(1); default: fprintf(stderr, "Unimplemented GLUT key "); //exit(1); } float FoV = initialFoV; ProjectionMatrix = glm::perspective(glm::radians(FoV), 4.0f / 3.0f, 0.1f, 100.0f); ViewMatrix = glm::lookAt( position, position + direction, up ); ModelMatrix = glm::mat4(1.0); MVP = ProjectionMatrix * ViewMatrix * ModelMatrix; glutPostRedisplay();//设置窗口重绘 } //传递鼠标事件 static void PassiveMouseCB(int x, int y) { horizontalAngle += mouseSpeed * float(x - mouseX); verticalAngle += mouseSpeed * float(y - mouseY); mouseX = x; mouseY = y; SpecialKeyboardCB(0, 0, 0); } //渲染回调函数 void RenderScenceCB() { // 清空颜色缓存 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//线框模式 //传递mvp glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); //传递顶点、索引 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); ////test //glDrawElements(GL_TRIANGLES, 3*4, GL_UNSIGNED_SHORT, 0); glDrawElements(GL_TRIANGLES_ADJACENCY, (longPart - 1)* latPart * 3 * 2 * 4, GL_UNSIGNED_SHORT, 0); glDisableVertexAttribArray(0); //交换前后缓存 glutSwapBuffers(); } //创建顶点 static void CreateVertexBuffer() { ////test //vertices = new GLfloat[3* 3]; //vertices[0] = -1.0f; //vertices[1] = -1.0f; //vertices[2] = -1.0f; //vertices[3] = -1.0f; //vertices[4] = -1.0f; //vertices[5] = 1.0f; //vertices[6] = -1.0f; //vertices[7] = 1.0f; //vertices[8] = 1.0f; vertices= new GLfloat[verticeNum * 3]; for (int i = 0; i < longPart; i++) { vertices[i * 3] = 0; vertices[i * 3 + 1] = 0; vertices[i * 3 + 2] = radius; } float degreesToRadians = 3.141593f/ 180.0f; //弧度转换 float deltaLong = 360.0f / (longPart - 1);//经度每份对应度数 float deltaLat = 180.0f / (latPart + 2);//纬度每份对应度数 for (int tempLat = 0; tempLat < latPart; tempLat++) { float tempAngle1 = ((tempLat + 1)* deltaLat) * degreesToRadians; for (int tempLong = 0; tempLong < longPart; tempLong++) { float tempAngle2 = (tempLong*deltaLong) * degreesToRadians; int tempIndex = tempLong + tempLat* longPart + longPart; vertices[tempIndex * 3] = sin(tempAngle1) * cos(tempAngle2)* radius; vertices[tempIndex * 3 + 1] = sin(tempAngle1) * sin(tempAngle2)* radius; vertices[tempIndex * 3 + 2] = cos(tempAngle1)* radius; } } for (int i = 0; i < longPart; i++) { vertices[(verticeNum - 1 - i) * 3] = 0; vertices[(verticeNum - 1 - i) * 3 + 1] = 0; vertices[(verticeNum - 1 - i) * 3 + 2] = -1.0f*radius; } glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); ////test //glBufferData(GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, verticeNum * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); } //创建索引 static void CreateIndexBuffer() { ////test //indices = new unsigned int[3]; //indices[0] = 2; //indices[1] = 1; //indices[2] = 0; indices = new unsigned int[(longPart - 1)* latPart * 3 * 2]; int k = 0; for (int i = 0; i < longPart - 1; i++) { indices[k++] = i; indices[k++] = i + longPart; indices[k++] = i + longPart + 1; } for (int tempLat = 0; tempLat < latPart-1; tempLat++) { for (int tempLong = 0; tempLong < longPart - 1; tempLong++) { indices[k++] = tempLong + tempLat * longPart + longPart; indices[k++] = tempLong + tempLat * longPart + 2 * longPart; indices[k++] = tempLong + tempLat * longPart + longPart + 1; indices[k++] = tempLong + tempLat * longPart + 2 * longPart; indices[k++] = tempLong + tempLat * longPart + 1 + 2 * longPart; indices[k++] = tempLong + tempLat * longPart + 1 + longPart; } } for (int i = 0; i < longPart - 1; i++) { indices[k++] = verticeNum - 1 - i; indices[k++] = verticeNum - 1 - i - longPart; indices[k++] = verticeNum - 2 - i - longPart; } glGenBuffers(1, &IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); ////test //glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3* sizeof(unsigned int), indices, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (longPart - 1)* latPart * 3 * 2 * sizeof(unsigned int), indices, GL_STATIC_DRAW); } // 使用shader文本编译shader对象,并绑定shader到着色器程序中 static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType) { // 根据shader类型参数定义两个shader对象 GLuint ShaderObj = glCreateShader(ShaderType); // 检查是否定义成功 if (ShaderObj == 0) { fprintf(stderr, "Error creating shader type %d ", ShaderType); exit(0); } // 定义shader的代码源 const GLchar* p[1]; p[0] = pShaderText; GLint Lengths[1]; Lengths[0] = strlen(pShaderText); glShaderSource(ShaderObj, 1, p, Lengths); glCompileShader(ShaderObj);// 编译shader对象 // 检查和shader相关的错误 GLint success; glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success); if (!success) { GLchar InfoLog[1024]; glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog); fprintf(stderr, "Error compiling shader type %d: '%s' ", ShaderType, InfoLog); exit(1); } // 将编译好的shader对象绑定到program object程序对象上 glAttachShader(ShaderProgram, ShaderObj); } // 编译着色器函数 static void CompileShaders() { // 创建着色器程序 ShaderProgram = glCreateProgram(); // 检查是否创建成功 if (ShaderProgram == 0) { fprintf(stderr, "Error creating shader program "); exit(1); } // 存储着色器文本的字符串 string vs, fs; // 分别读取着色器文件中的文本到字符串 std::ifstream VertexShaderStream(vsShaderName, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); vs = sstr.str(); VertexShaderStream.close(); } else { printf("Error to open %s ", vsShaderName); getchar(); exit(0); } std::ifstream FragmentShaderStream(fsShaderName, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); fs = sstr.str(); FragmentShaderStream.close(); } // 添加顶点着色器和片段着色器 AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER); AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER); // 链接shader着色器程序,并检查程序相关错误 GLint Success = 0; GLchar ErrorLog[1024] = { 0 }; glLinkProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); if (Success == 0) { glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, "Error linking shader program: '%s' ", ErrorLog); exit(1); } // 检查验证在当前的管线状态程序是否可以被执行 glValidateProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success); if (!Success) { glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, "Invalid shader program: '%s' ", ErrorLog); exit(1); } // 设置到管线声明中来使用上面成功建立的shader程序 glUseProgram(ShaderProgram); MatrixID = glGetUniformLocation(ShaderProgram, "gWVP"); } int main(int argc, char ** argv) { // 初始化GLUT glutInit(&argc, argv); // 显示模式:双缓冲、RGBA glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(100, 100); glutCreateWindow("sphere"); GLenum res = glewInit(); if (res != GLEW_OK) { fprintf(stderr, "Error: '%s' ", glewGetErrorString(res)); return 1; } // 开始渲染 glutDisplayFunc(RenderScenceCB); // 注册键盘事件 glutSpecialFunc(SpecialKeyboardCB); //注册鼠标事件 glutPassiveMotionFunc(PassiveMouseCB); mouseX = windowWidth / 2; mouseY = windowHeight / 2; // 缓存清空后的颜色值 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //创建顶点 CreateVertexBuffer(); //创建索引 CreateIndexBuffer(); // 编译着色器 CompileShaders(); //开启深度测试 glEnable(GL_DEPTH_TEST); // 通知开始GLUT的内部循环 glutMainLoop(); delete vertices; return 0; }
shader.vs如下
#version 330 layout (location = 0) in vec3 Position; // WVP标准 uniform mat4 gWVP; void main() { gl_Position = gWVP * vec4(Position, 1.0); }
shader.fs如下
#version 330 out vec3 FragColor; void main() { FragColor = vec3(1.0, 0.0, 0.0); }