准備第三方庫 glew、freeglut、glm、opencv
准備灰度圖片和草地貼圖


最終效果

代碼包括主程序源文件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 <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> using namespace std; using namespace cv; using namespace glm; //shader文件 const char* vsShaderName = "shader.vs";//頂點着色器 const char* fsShaderName = "shader.fs";//片元着色器 GLuint VBO;//頂點緩沖對象 GLuint IBO;//索引緩沖對象 GLuint UVBO;//uv緩沖對象 GLuint TexBO;//貼圖對象 static GLfloat *vertices; static unsigned int *indices; static GLfloat *uvs; GLuint ShaderProgram; GLuint MatrixID; GLuint TextureID; int windowWidth = 800; int windowHeight=800; int imgWidth; int imgHeihgt; float verticeScale = 0.1f; float ZScale = 5.0f; //相機參數 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.005f; 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\n"); break; case GLUT_KEY_RIGHT: position += right * speed; fprintf(stderr, "right key\n"); break; case GLUT_KEY_DOWN: position -= direction * speed; fprintf(stderr, "down key\n"); break; case GLUT_KEY_LEFT: position -= right * speed; fprintf(stderr, "left key\n"); break; case GLUT_KEY_F4: exit(1); default: fprintf(stderr, "Unimplemented GLUT key\n"); //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); //傳遞mvp glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); //傳遞頂點、索引、UV glEnableVertexAttribArray(0); //開啟頂點屬性 glBindBuffer(GL_ARRAY_BUFFER, VBO); //綁定GL_ARRAY_BUFFER緩沖器 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); //告訴管線怎樣解析bufer中的數據 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, UVBO); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); //傳遞貼圖紋理 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, TexBO); glUniform1i(TextureID, 0); //繪制 glDrawElements(GL_TRIANGLES, (imgWidth - 1)*(imgHeihgt - 1) * 6*4, GL_UNSIGNED_SHORT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); //交換前后緩存 glutSwapBuffers(); } //創建頂點 static void CreateVertexBuffer() { //讀取圖片 Mat img = imread("T2.png"); int imgType = img.type(); #pragma region 灰度圖信息 // C1 C2 C3 C4 //CV_8U 0 8 16 24 //CV_8S 1 9 17 25 //CV_16U 2 10 18 26 //CV_16S 3 11 19 27 //CV_32S 4 12 20 28 //CV_32F 5 13 21 29 //CV_64F 6 14 22 30 //fprintf(stderr, "Gray img type %d\n", imgType); //16 即是CV_8UC3 //imshow("grayImgTestShow",img); #pragma endregion Mat resImg = Mat(img.rows, img.cols, imgType); resize(img, resImg, resImg.size(), 0, 0, INTER_LINEAR); Mat gImg = Mat(img.rows,img.cols,CV_8UC1); //灰度圖 cv::cvtColor(resImg, gImg, CV_BGR2GRAY);//bgr轉灰度 imgWidth = resImg.rows; imgHeihgt = resImg.cols; //fprintf(stderr,"image gray type %d",resImg.type()); vertices = new GLfloat[imgWidth*imgHeihgt*3]; int k = 0; for (int i = 0; i < imgWidth; i++) { for (int j = 0; j < imgHeihgt; j++) { vertices[k++] = verticeScale* (float)i; vertices[k++] = verticeScale*(float)j; int c = (int)gImg.at<uchar>(i, j); //fprintf(stderr,"gray color %d %d %d",i,j ,(int)gImg.at<uchar>(i, j)); vertices[k++] = ZScale*(float)c / 255.0f; } } glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, imgWidth*imgHeihgt * 3*sizeof(GLfloat), vertices, GL_STATIC_DRAW); } //創建索引 static void CreateIndexBuffer() { indices = new unsigned int[(imgWidth-1)*(imgHeihgt-1) * 6]; int k = 0; for (int i = 0; i < imgWidth - 1; i++) { for (int j = 0; j < imgHeihgt - 1; j++) { indices[k++] = i*imgHeihgt + j; indices[k++] = i*imgHeihgt + j + 1; indices[k++] = i*imgHeihgt + j + imgHeihgt; indices[k++] = i*imgHeihgt + j + imgHeihgt; indices[k++] = i*imgHeihgt + j + 1; indices[k++] = i*imgHeihgt + j + imgHeihgt + 1; } } glGenBuffers(1, &IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (imgWidth - 1)*(imgHeihgt - 1) * 6*sizeof(unsigned int), indices, GL_STATIC_DRAW); } //創建uv static void CreateUVBuffer() { uvs=new GLfloat[imgWidth*imgHeihgt * 2]; int k = 0; for (int i = 0; i < imgWidth; i++) { for (int j = 0; j < imgHeihgt; j++) { uvs[k++] = (float)i / (float)(imgWidth); uvs[k++] = (float)j / (float)(imgHeihgt); } } glGenBuffers(1, &UVBO); glBindBuffer(GL_ARRAY_BUFFER, UVBO); glBufferData(GL_ARRAY_BUFFER, imgWidth*imgHeihgt * 2 * sizeof(GLfloat), uvs, GL_STATIC_DRAW); } //創建貼圖 static void CreateTexture() { Mat img = imread("grass.jpg"); Mat resImg = Mat(256, 256, img.type()); resize(img, resImg, resImg.size(), 0, 0, INTER_LINEAR); cv::cvtColor(resImg, resImg, CV_BGR2RGB); glGenTextures(1, &TexBO); glBindTexture(GL_TEXTURE_2D, TexBO); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, resImg.data);//設定紋理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//重復紋理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//濾波 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); TextureID = glGetUniformLocation(ShaderProgram, "myTexture"); } // 使用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\n", 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'\n", ShaderType, InfoLog); exit(1); } // 將編譯好的shader對象綁定到program object程序對象上 glAttachShader(ShaderProgram, ShaderObj); } // 編譯着色器函數 static void CompileShaders() { // 創建着色器程序 ShaderProgram = glCreateProgram(); // 檢查是否創建成功 if (ShaderProgram == 0) { fprintf(stderr, "Error creating shader program\n"); 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\n", 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'\n", 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'\n", 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("terrainTest1"); // 窗口標題 GLenum res = glewInit(); if (res != GLEW_OK) { fprintf(stderr, "Error: '%s'\n", 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(); //創建uv CreateUVBuffer(); //創建貼圖 CreateTexture(); // 編譯着色器 CompileShaders(); //開啟深度測試 glEnable(GL_DEPTH_TEST); // 通知開始GLUT的內部循環 glutMainLoop(); delete vertices; return 0; }
shader.vs 如下
#version 330 layout (location = 0) in vec3 Position; layout(location = 1) in vec2 vertexUV; // WVP標准 uniform mat4 gWVP; out vec2 UV; void main() { gl_Position = gWVP * vec4(Position, 1.0); UV = vertexUV; }
shader.fs如下
#version 330 in vec2 UV; out vec3 FragColor; uniform sampler2D myTexture; void main() { FragColor = texture( myTexture, UV ).rgb; }
參考鏈接
本文鏈接