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

    转自:https://www.cnblogs.com/gucheng/p/10152889.html

    准备第三方库 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;//贴图对象
    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);<br>     //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;
    }

    shader.vs

    #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;
    }

    shader.fs

    #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);   
         
    }
  • 相关阅读:
    Hello Springboot
    Spring AOP
    代理模式
    Spring 面向注解开发
    Spring Bean 的配置
    IDEA 14 for Mac 提示要安装java 6的修改
    NAS DIY
    Maven Jetty SSL配置
    图书管理系统(jsp+nysql实现)
    互联网+XX项目技术架构
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/11797341.html
Copyright © 2011-2022 走看看