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

  • 相关阅读:
    [SHOI2015]脑洞治疗仪
    [SDOI2016]数字配对
    [SDOI2019]快速查询
    [HNOI2019]JOJO
    [TJOI2019]甲苯先生和大中锋的字符串
    [CQOI2017]老C的方块
    [CQOI2017] 小Q的表格
    [SHOI2012] 火柴游戏
    板子
    自我介绍
  • 原文地址:https://www.cnblogs.com/gucheng/p/10152889.html
Copyright © 2011-2022 走看看