zoukankan      html  css  js  c++  java
  • opengl读取灰度图生成三维地形并添加光照

    准备第三方库 glew、freeglut、glm、opencv
    准备一张灰度图
    最终效果
    代码如下
    #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;//贴图对象
    GLuint NormalBO;//法线对象
    //光照定义
    struct {
    	GLuint Color;//颜色
    	GLuint AmbientIntensity;//环境光强度
    	GLuint Direction;//方向
    	GLuint DiffuseIntensity;//漫反射强度
    } m_dirLightLocation; 
    static  GLfloat *vertices;
    static unsigned int *indices;
    static  GLfloat *uvs;
    static GLfloat *normals;
    
    GLuint ShaderProgram;
    GLuint MatrixID;
    GLuint MatrixID2;
    GLuint TextureID;
    
    int windowWidth = 1000;
    int windowHeight = 800;
    int imgWidth;
    int imgHeihgt;
    float verticeScale = 0.1f;
    float yScale = 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;//鼠标位置 窗口坐标
    bool mouseLeftDown = false;//鼠标左键按下 
    
    // 传递键盘事件
    static void SpecialKeyboardCB(unsigned char 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 'w':
    		position += direction  * speed;
    		//fprintf(stderr, "up 
    ");
    		break;
    	case 'd':
    		position += right  * speed;
    		//fprintf(stderr, "right 
    ");
    		break;
    	case 's':
    		position -= direction  * speed;
    		//fprintf(stderr, "down 
    ");
    		break;
    	case 'a':
    		position -= right  * speed;
    		//fprintf(stderr, "left 
    ");
    		break;
    	case 27:
    		exit(1);
    		break;
    	default:
    		break;
    		//fprintf(stderr, "Unimplemented GLUT key
    ");
    		//exit(1); 
    	}
    
    	float FoV = initialFoV;
    	ProjectionMatrix = glm::perspective(glm::radians(FoV), (float)windowWidth / (float)windowHeight, 0.1f, 100.0f);
    	ViewMatrix = glm::lookAt(
    		position,
    		position + direction,
    		up
    	);
    	ModelMatrix = glm::mat4(1.0);
    	MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
    	glutPostRedisplay();//设置窗口重绘
    }
    
    //传递鼠标事件
    void mouseCB(int button, int state, int x, int y)
    {
    	if (button == GLUT_LEFT_BUTTON)
    	{
    		if (state == GLUT_DOWN)
    		{
    			mouseLeftDown = true;
    			mouseX = x;
    			mouseY = y;
    		}
    		else if (state == GLUT_UP)
    		{
    			mouseLeftDown = false;
    		}
    	}
    }
    
    //传递鼠标位置
    static void mouseMotionCB(int x, int y)
    {
    	if (mouseLeftDown == true)
    	{
    		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);//线框模式 //传递矩阵数据 glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); glUniformMatrix4fv(MatrixID2,1, GL_FALSE,&ModelMatrix[0][0]); //传递光照 glUniform3f(m_dirLightLocation.Color, 1, 1, 0); glUniform1f(m_dirLightLocation.AmbientIntensity, 0.5); glUniform3f(m_dirLightLocation.Direction,1,1,0); glUniform1f(m_dirLightLocation.DiffuseIntensity,0.7); //传递顶点、索引、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); glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, NormalBO); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); //传递贴图纹理 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, TexBO); glUniform1i(TextureID, 0); //绘制 glDrawElements(GL_TRIANGLES_ADJACENCY, (imgWidth - 1)*(imgHeihgt - 1) * 6 * 4, GL_UNSIGNED_SHORT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); //交换前后缓存 glutSwapBuffers(); } //创建顶点 static void CreateVertexBuffer() { //读取图片 Mat img = imread("T2.png"); int imgType = img.type(); 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; vertices = new GLfloat[imgWidth*imgHeihgt * 3]; int k = 0; for (int i = 0; i < imgHeihgt; i++) { for (int j = 0; j < imgWidth; j++) { vertices[k++] = verticeScale* (float)i; int c = (int)gImg.at<uchar>(j, i); vertices[k++] = yScale*(float)c / 255.0f; vertices[k++] = verticeScale*(float)j; } } 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 < imgHeihgt - 1; i++) { for (int j = 0; j < imgWidth - 1; j++) { indices[k++] = i*imgWidth + j; indices[k++] = i*imgWidth + j + 1; indices[k++] = i*imgWidth + j + imgWidth; indices[k++] = i*imgWidth + j + imgWidth; indices[k++] = i*imgWidth + j + 1; indices[k++] = i*imgWidth + j + imgWidth + 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 < imgHeihgt; i++) { for (int j = 0; j < imgWidth; j++) { uvs[k++] = (float)i / (float)(imgHeihgt); uvs[k++] = (float)j / (float)(imgWidth); } } 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("T2.png"); 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"); } //创建法线 static void CreateNormal() { normals= new GLfloat[imgWidth*imgHeihgt*3]; int k = 0; //遍历索引三角 for (size_t i = 0; i < (imgWidth - 1)*(imgHeihgt - 1) * 6; i+=3) { static unsigned int pIndex1 = indices[i]; static unsigned int pIndex2 = indices[i + 1]; static unsigned int pIndex3 = indices[i + 2]; static float x1 = vertices[pIndex1]; static float y1 = vertices[pIndex1 + 1]; static float z1 = vertices[pIndex1 + 2]; static float x2 = vertices[pIndex2]; static float y2 = vertices[pIndex2 + 1]; static float z2 = vertices[pIndex2 + 2]; static float x3 = vertices[pIndex3]; static float y3 = vertices[pIndex3 + 1]; static float z3 = vertices[pIndex3 + 2]; //求边 static float vx1 = x2 - x1; static float vy1 = y2 - y1; static float vz1 = z2 - z1; static float vx2 = x3 - x1; static float vy2 = y3 - y1; static float vz2 = z3 - z1; //叉乘求三角形法线 static float xN = vy1 * vz2 - vz1 *vy2; static float yN = vz1 * vx2 - vx1 * vz2; static float zN = vx1 * vy2 - vy1 * vx2; static float Length = sqrtf(xN * xN + yN * yN + zN * zN); xN /= Length; yN /= Length; zN /= Length; //顶点法线更新 normals[pIndex1] += xN; normals[pIndex1 + 1] += yN; normals[pIndex1 + 2] += zN; normals[pIndex2] += xN; normals[pIndex2 + 1] += yN; normals[pIndex2 + 2] += zN; normals[pIndex3] += xN; normals[pIndex3 + 1] += yN; normals[pIndex3 + 2] += zN; } glGenBuffers(1, &NormalBO); glBindBuffer(GL_ARRAY_BUFFER, NormalBO); glBufferData(GL_ARRAY_BUFFER, imgWidth*imgHeihgt * 3 * sizeof(GLfloat), normals, 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); } glUseProgram(ShaderProgram); //统一变量位置 MatrixID = glGetUniformLocation(ShaderProgram, "gWVP"); MatrixID2= glGetUniformLocation(ShaderProgram, "gWorld"); m_dirLightLocation.Color = glGetUniformLocation(ShaderProgram,"gDirectionalLight.Color"); m_dirLightLocation.AmbientIntensity = glGetUniformLocation(ShaderProgram,"gDirectionalLight.AmbientIntensity"); m_dirLightLocation.Direction = glGetUniformLocation(ShaderProgram,"gDirectionalLight.Direction"); m_dirLightLocation.DiffuseIntensity = glGetUniformLocation(ShaderProgram,"gDirectionalLight.DiffuseIntensity"); } int main(int argc, char ** argv) { // 初始化GLUT glutInit(&argc, argv); // 显示模式:双缓冲、RGBA glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); // 窗口设置 glutInitWindowSize(windowWidth, windowHeight); // 窗口尺寸 glutInitWindowPosition(100, 100); // 窗口位置 glutCreateWindow("terrainTest2"); // 窗口标题 GLenum res = glewInit(); if (res != GLEW_OK) { fprintf(stderr, "Error: '%s' ", glewGetErrorString(res)); return 1; } // 开始渲染 glutDisplayFunc(RenderScenceCB); // 注册键盘事件 glutKeyboardFunc(SpecialKeyboardCB); //注册鼠标事件 glutMouseFunc(mouseCB); glutMotionFunc(mouseMotionCB); mouseX = windowWidth / 2; mouseY = windowHeight / 2; // 缓存清空后的颜色值 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //创建顶点 CreateVertexBuffer(); //创建索引 CreateIndexBuffer(); //创建uv CreateUVBuffer(); //创建贴图 CreateTexture(); //创建法线 CreateNormal(); // 编译着色器 CompileShaders(); //开启深度测试 glEnable(GL_DEPTH_TEST); // 通知开始GLUT的内部循环 glutMainLoop(); delete vertices; return 0; }
    #version 330
    layout (location = 0) in vec3 Position;
    layout (location = 1) in vec2 vertexUV; 
    layout (location = 2) in vec3 Normal;
    uniform mat4 gWVP; 
    uniform mat4 gWorld;
    out vec2 UV; 
    out vec3 Normal0;
    void main()
    {
        gl_Position = gWVP * vec4(Position, 1.0);
        UV = vertexUV;
        Normal0 = (gWorld * vec4(Normal, 0.0)).xyz;
    }
    
    #version 330
    in vec2 UV; 
    in vec3 Normal0;    
    out vec4 FragColor;   
    //光照 
    struct DirectionalLight                                                             
    {                                                                                   
        vec3 Color;                                                                     
        float AmbientIntensity;                                                         
        float DiffuseIntensity;                                                         
        vec3 Direction;                                                                 
    };                                                                                   
    uniform DirectionalLight gDirectionalLight;       
    uniform sampler2D myTexture; 
    void main()
    {  
    //环境光
        vec4 AmbientColor = vec4(gDirectionalLight.Color, 1.0f) *                       
                            gDirectionalLight.AmbientIntensity;                         
     //漫反射                                                                                   
        float DiffuseFactor = dot(normalize(Normal0), -gDirectionalLight.Direction);     
        vec4 DiffuseColor;                                                                
        if (DiffuseFactor > 0) {                                                        
            DiffuseColor = vec4(gDirectionalLight.Color, 1.0f) *                        
                           gDirectionalLight.DiffuseIntensity *                         
                           DiffuseFactor;                                               
        }                                                                               
        else {                                                                          
            DiffuseColor = vec4(0, 0, 0, 0);                                            
        }                                                                                
        FragColor = texture2D(myTexture, UV.xy) *                                 
                    (AmbientColor + DiffuseColor);    
        
    }
    

    参考链接https://blog.csdn.net/cordova/column/info/13062

    本文链接https://www.cnblogs.com/gucheng/p/10152889.html

  • 相关阅读:
    redis发布订阅
    redis学习笔记(面试题)
    redis安全 (error) NOAUTH Authentication required
    HDU3001 Travelling —— 状压DP(三进制)
    POJ3616 Milking Time —— DP
    POJ3186 Treats for the Cows —— DP
    HDU1074 Doing Homework —— 状压DP
    POJ1661 Help Jimmy —— DP
    HDU1260 Tickets —— DP
    HDU1176 免费馅饼 —— DP
  • 原文地址:https://www.cnblogs.com/gucheng/p/10152889.html
Copyright © 2011-2022 走看看