OpenGL半球贴图
#version 330 core out vec4 FragColor; in vec2 tex_coord; uniform sampler2D tex; void main() { //FragColor = vec4(1.0,0.635,0.345,1.0); FragColor = texture(tex, tex_coord); }
#version 330 core layout (location = 0) in vec3 aPos; uniform mat4 face_matrix; out vec2 tex_coord; void main() { float dist = 2*sqrt(pow(aPos.x,2)+pow(aPos.y,2)+pow(aPos.z,2)); vec4 vpos = face_matrix *vec4(aPos.x/dist,aPos.y/dist,aPos.z/dist,1.0);//顶点坐标旋转 tex_coord = vec2((aPos.x+1)/2 ,(aPos.z+1)/2); // -1~1 移动到0~1;((*+1)/2),写错了可能会有黑条(不要去乘MVP) gl_Position = vpos; }
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <shader.h> #include <iostream> #include <math.h> #include <vector> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <windows.h> #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" const unsigned int screen_width = 780; const unsigned int screen_height = 780; const GLfloat PI = 3.14159265358979323846f; //将球横纵划分成X*Y的网格 const int Y_SEGMENTS = 40; const int X_SEGMENTS = 40; ; unsigned int testureID = 99; glm::mat4 pos_matrix, face_matrix, projection; GLuint pos_matrix_idx, face_matrix_idx,projID; 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("vertexShader.glsl", "fragmentShader.glsl");//加载,编译着色器 //加载图片 //加载图片----------------------------------------------------------------- shader.use(); glGenTextures(1, &testureID); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, testureID); //为bind的纹理设置环绕,过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //stbi是一个图片载入的开源组件,文件名,宽高,通道数,你期望的通道数 int W, H, desired_channels; //注意图片是24位的 unsigned char* data = stbi_load("./21.jpg", &W, &H, &desired_channels, 0); if (data) { //数据生成纹理;根据指定的参数,把输入数据生成一张2D纹理 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, W, H, 0, GL_RGB, GL_UNSIGNED_BYTE, data); //生成mipmap数组 glUniform1i(glGetUniformLocation(shader.ID, "tex"), 0);//这句话一定要写,不然没法采样 glGenerateMipmap(GL_TEXTURE_2D); } stbi_image_free(data); //----------------------------------------------------------- std::vector<float> sphereVertices; // Y_SEGMENTS 和 X_SEGMENTS 分别表 示将α 和β 分割了多少份, //y 和 x 分别表示是第几份,以此进行遍历, xSegment*2.0f*PI 即β 角,ySegment*PI 即α 角。 for (int y = -(Y_SEGMENTS / 2); y <= 0; 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::cos(ySegment * PI); float yPos = std::sin(ySegment * PI); float zPos = std::sin(xSegment * 2.0f * PI) * std::cos(ySegment * PI); sphereVertices.push_back(xPos); sphereVertices.push_back(yPos); sphereVertices.push_back(zPos); } } // 生成球的三角形索引;六个点两个三角; std::vector<int> sphereIndices; for (int i = 0; i < Y_SEGMENTS/2 ; 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); // pos_matrix_idx = glGetUniformLocation(shader.ID, "pos_matrix"); //projID = glGetUniformLocation(shader.ID, "projection"); glm::mat4 view = glm::mat4(1.0f); ////平移 //pos_matrix = glm::translate(view, glm::vec3(0.0f, 0.00f, 0.0f)); //glUniformMatrix4fv(pos_matrix_idx, 1, GL_FALSE, &pos_matrix[0][0]); ////旋转 //face_matrix = glm::rotate(view, glm::radians(30.0f), glm::vec3(0.0f, 1.0f, 0.0f)); //glUniformMatrix4fv(face_matrix_idx, 1, GL_FALSE, &face_matrix[0][0]); ////s视角 //projection = glm::perspective((float)glfwGetTime(), (float)screen_width / (float)screen_height, 0.1f, 10.0f); //glUniformMatrix4fv(projID, 1, GL_FALSE, &projection[0][0]); //------------------------------------------------------------------------------- int i = 0; // 渲染循环 while (!glfwWindowShouldClose(window)) { // 清空颜色缓冲 glClearColor(0.0f, 0.3f, 0.2f, 1.0f); i = (i++)% 12; //旋转 face_matrix = glm::rotate(view, glm::radians(30.0f*i), glm::vec3(1.0f, 0.0f, 0.0f)); face_matrix_idx = glGetUniformLocation(shader.ID, "face_matrix"); glUniformMatrix4fv(face_matrix_idx, 1, GL_FALSE, &face_matrix[0][0]); shader.use(); //绘制球 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glClearDepth(1.0); glEnable(GL_DEPTH_TEST); glBindVertexArray(VAO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindBuffer(GL_ARRAY_BUFFER, VAO); glDrawElements(GL_TRIANGLES,(X_SEGMENTS)*(Y_SEGMENTS/2) * 6, GL_UNSIGNED_INT, (GLvoid *)(0)); glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents(); Sleep(2000);//1s } // 删除VAO和VBO,EBO glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &element_buffer_object); // 清理所有的资源并正确退出程序 glfwTerminate(); return 0; }
半球贴图:旋转过程截图
原图: