源码效果
C++源码
纹理图片
需下载stb_image.h这个解码图片的库,该库只有一个头文件。
具体代码:
vertexShader.glsl
#version 330 corelayout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix;
uniform mat4 _viewMatrix;
uniform mat4 _projMatrix;void main()
{gl_Position = _projMatrix* _viewMatrix * _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);outUV = aUV;
}
fragmentShader.glsl
#version 330 coreout vec4 FragColor;in vec2 outUV;uniform sampler2D ourTexture;void main()
{// 使用图片纹理及色彩混合FragColor = texture(ourTexture, outUV);
}
main.cpp
#include "OpenGLClass.h"
#include "OpenGLClass.h"int main()
{OpenGLClass opengl;return 0;
}
OpenGLClass.h
#pragma once#include "Global.h"
#include "ffImage.h"class OpenGLClass
{
public:OpenGLClass();~OpenGLClass();protected:// 初始化纹理bool initTexture();// 初始化模型VAO/VBOvoid initModel();// 初始化shader文件bool initShader(const char *_vertexPath, const char *_fragPath);// 读取glsl文件内容std::string ReadGlslContext(const char *sPath);// 刷新Rendervoid FlushRender();// 回调 - 窗口尺寸变化回调static void bck_GLFWframebuffersizefun(GLFWwindow* window, int width, int height);// 处理按键输入void ProcessKeyPInput(GLFWwindow *window);// 设置矩阵void setMatrix(const std::string &_name, glm::mat4 _matrix)const;private:unsigned short windowWidth = 800, windowHeight = 600;unsigned int shaderProgram = 0; // 链接程序对象unsigned int VBO = 0, VAO = 0, _texture = 0;
};
OpenGLClass.cpp
#include "OpenGLClass.h"void OpenGLClass::bck_GLFWframebuffersizefun(GLFWwindow* window, int width, int height)
{// 在窗口中定义一个像素矩形,最终的图形将映射到个矩形中glViewport(0, 0, width, height);
}OpenGLClass::OpenGLClass()
{// 初始化glfw上下文if (glfwInit() == GLFW_FALSE) { std::cout << "glfwInit fail!\n"; return; }glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 3.3版本glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用OpenGL核心模式// 创建OpenGL窗体GLFWwindow *window = glfwCreateWindow(windowWidth, windowHeight, "OpenGL Core", nullptr, nullptr);if (!window) { std::cout << "glfwCreateWindow fail!\n"; return; }// 当前OpenGL上下文绑定窗口glfwMakeContextCurrent(window);// 加载所有OpenGL函数指针if (GL_FALSE == gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "gladLoadGLLoader fail!\n"; return; }// 在窗口中定义一个像素矩形,最终的图形将映射到个矩形中glViewport(0, 0, windowWidth, windowHeight);// 窗口大小调整回调glfwSetFramebufferSizeCallback(window, OpenGLClass::bck_GLFWframebuffersizefun);// 初始化VAO/VBOinitModel();// 初始化纹理if (!initTexture()) { std::cout << "initTexture fail!\n"; system("pause"); return; }// 初始化shaderif (!initShader("vertexShader.glsl", "fragmentShader.glsl")) { std::cout << "initShader fail!\n"; system("pause"); return; }// 窗口标志是否是关闭while (!glfwWindowShouldClose(window)){// 输入按键处理ProcessKeyPInput(window);#if 0// 使用红,绿,蓝以及alpha值来清除颜色缓冲区glClearColor(0.328125f, 0.35156f, 0.82421f, 1.0f);// 将从窗口中清除最后一次所绘制的图形/*GL_COLOR_BUFFER_BIT: 当前可写的颜色缓冲GL_DEPTH_BUFFER_BIT: 深度缓冲GL_ACCUM_BUFFER_BIT: 累积缓冲GL_STENCIL_BUFFER_BIT: 模板缓冲*/glClear(GL_COLOR_BUFFER_BIT);
#endifFlushRender();// 双缓冲,使用OpenGL或OpenGL ES进行渲染glfwSwapBuffers(window);// glfw事件循环glfwPollEvents();// 睡眠10ms,防止造成GPU疯狂消耗。实际具体调整Sleep(10);}// 释放窗口glfwDestroyWindow(window);// 释放资源,终止GLFW库glfwTerminate();
}OpenGLClass::~OpenGLClass()
{// 释放if (glIsProgram(shaderProgram)) { glDeleteProgram(shaderProgram); }shaderProgram = 0;if (glIsBuffer(VAO)) { glDeleteBuffers(1, &VAO); } VAO = 0;if (glIsBuffer(VBO)) { glDeleteBuffers(1, &VBO); } VBO = 0;
}void OpenGLClass::ProcessKeyPInput(GLFWwindow *window)
{if (window){// 获取窗口按键是否ESCif (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){// 设置窗口关闭标志glfwSetWindowShouldClose(window, true);}}window = nullptr;
}void OpenGLClass::setMatrix(const std::string &_name, glm::mat4 _matrix) const
{// 获得指定shader程序中uniform变量的位置int shaderNameId = glGetUniformLocation(shaderProgram, _name.c_str());/*将4x4的矩阵数据传递给着色器location:指定要更改的uniform变量的位置。count:指定要更改的矩阵的数量。如果只更改一个矩阵,该值为1。transpose:指定是否需要将矩阵进行转置。一般情况下,设为GL_FALSE即可。value:指向包含矩阵数据的指针。*/glUniformMatrix4fv(shaderNameId,1,GL_FALSE,glm::value_ptr(_matrix));
}void OpenGLClass::FlushRender()
{// 判断VAO是否被删除if (glIsVertexArray(VAO)){// 使用红,绿,蓝以及alpha值来清除颜色缓冲区glClearColor(0.328125f, 0.35156f, 0.82421f, 1.0f);// 将从窗口中清除最后一次所绘制的图形,GL_DEPTH_BUFFER_BIT将深度信息也清除glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 开启深度检测glEnable(GL_DEPTH_TEST);/// // 模型平移数据glm::vec3 modelVecs[] ={glm::vec3(0.0f,0.0f,0.0f),glm::vec3(2.0f, 5.0f, -15.0f),glm::vec3(-1.5f, -2.2f, -2.5f),glm::vec3(-3.8f, -2.0f, -12.3f),glm::vec3(2.4f, -0.4f, -3.5f),glm::vec3(-1.7f, 3.0f, -7.5f),glm::vec3(1.3f, -2.0f, -2.5f),glm::vec3(1.5f, 2.0f, -2.5f),glm::vec3(1.5f, 0.2f, -1.5f),glm::vec3(-1.3f, 1.0f, -1.5f)};//////// 观察者/摄像机矩阵glm::mat4 _viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 2.4f), // 摄像机位置glm::vec3(0.0f, 0.0f, 0.0f), // 摄像机看向的位置glm::vec3(0.0f, 1.0f, 0.0f) // 摄像机顶部的位置);// 投影矩阵glm::mat4 _projMatrix = glm::perspective(glm::radians(45.0f),(float)windowWidth / (float)(windowHeight),0.1f, 100.0f);///// 使用程序glUseProgram(shaderProgram);// 绘制10个立方体for (unsigned short index = 0; index < 10; ++index){glm::mat4 _modelMatrix(1.0f);_modelMatrix = glm::translate(_modelMatrix, modelVecs[index]);_modelMatrix = glm::rotate(_modelMatrix, glm::radians((float)glfwGetTime()*(index + 1) * 10), glm::vec3(0.5f, 1.0f, 0.0f));///setMatrix("_modelMatrix", _modelMatrix);setMatrix("_viewMatrix", _viewMatrix);setMatrix("_projMatrix", _projMatrix);///// 绑定纹理glBindTexture(GL_TEXTURE_2D, _texture);// 绑定VAOglBindVertexArray(VAO);// 绘制三角形glDrawArrays(GL_TRIANGLES, 0, 36);}// 关闭使用程序glUseProgram(0);}
}bool OpenGLClass::initTexture()
{// 读取图片相关信息ffImage *pImage = ffImage::readFromFile("./rec/wall.jpeg");if (!pImage) { return false; }// 生成纹理glGenTextures(1, &_texture);// 以2D方式绑定纹理// 将当前绑定的纹理对象替换为参数中指定的纹理对象glBindTexture(GL_TEXTURE_2D, _texture);// 设置纹理属性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_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 读取图片数据,完成数据绑定glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pImage->getWidth(), pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pImage->getData());if (pImage) { delete pImage; }pImage = nullptr;return true;
}void OpenGLClass::initModel()
{// 坐标、颜色、纹理位置float vertices[]{-0.5f,-0.5f,-0.5f, 0.0f,0.0f,0.5f,-0.5f,-0.5f, 1.0f,0.0f,0.5f, 0.5f,-0.5f, 1.0f,1.0f,0.5f, 0.5f,-0.5f, 1.0f,1.0f,-0.5f, 0.5f,-0.5f, 0.0f,1.0f,-0.5f,-0.5f,-0.5f, 0.0f,0.0f,-0.5f,-0.5f,0.5f, 0.0f,0.0f,0.5f,-0.5f,0.5f, 1.0f,0.0f,0.5f, 0.5f,0.5f, 1.0f,1.0f,0.5f, 0.5f,0.5f, 1.0f,1.0f,-0.5f, 0.5f,0.5f, 0.0f,1.0f,-0.5f,-0.5f,0.5f, 0.0f,0.0f,-0.5f, 0.5f, 0.5f, 1.0f,0.0f,-0.5f, 0.5f,-0.5f, 1.0f,1.0f,-0.5f,-0.5f,-0.5f, 0.0f,1.0f,-0.5f,-0.5f,-0.5f, 0.0f,1.0f,-0.5f,-0.5f, 0.5f, 0.0f,0.0f,-0.5f, 0.5f, 0.5f, 1.0f,0.0f,0.5f, 0.5f, 0.5f, 1.0f,0.0f,0.5f, 0.5f,-0.5f, 1.0f,1.0f,0.5f,-0.5f,-0.5f, 0.0f,1.0f,0.5f,-0.5f,-0.5f, 0.0f,1.0f,0.5f,-0.5f, 0.5f, 0.0f,0.0f,0.5f, 0.5f, 0.5f, 1.0f,0.0f,-0.5f,-0.5f,-0.5f, 0.0f,1.0f,0.5f,-0.5f,-0.5f, 1.0f,1.0f,0.5f,-0.5f, 0.5f, 1.0f,0.0f,0.5f,-0.5f, 0.5f, 1.0f,0.0f,-0.5f,-0.5f, 0.5f, 0.0f,0.0f,-0.5f,-0.5f,-0.5f, 0.0f,1.0f,-0.5f,0.5f,-0.5f, 0.0f,1.0f,0.5f,0.5f,-0.5f, 1.0f,1.0f,0.5f,0.5f, 0.5f, 1.0f,0.0f,0.5f,0.5f, 0.5f, 1.0f,0.0f,-0.5f,0.5f, 0.5f, 0.0f,0.0f,-0.5f,0.5f,-0.5f, 0.0f,1.0f};/****************************************************/ // VAO// 创建VAOglGenVertexArrays(1, &VAO);// 绑定指定的顶点数组对象(Vertex Array Object, VAO)glBindVertexArray(VAO);/****************************************************//****************************************************/ // VBO// 生成缓冲区对象glGenBuffers(1, &VBO);// 绑定命名缓冲区对象glBindBuffer(GL_ARRAY_BUFFER, VBO);// 缓冲对象(VBO,IBO 等)分配空间并存储数据glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);/*指定顶点属性在顶点缓冲对象中的布局,并将其与顶点着色器中的顶点属性进行关联参数1:第n个layout (对应glsl中顶点着色器的layout)参数2:顶点属性的组成元素的数量,例如3表示顶点属性是由3个浮点数组成参数3:顶点属性的数据类型参数4:是否将非浮点型的数据归一化到[-1, 1]或[0, 1]范围内参数5:相邻两个顶点属性之间的字节数,通常为0或属性类型大小乘以数量参数6:顶点属性在顶点缓冲对象中的偏移量或者数据的首地址*/glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(sizeof(float) * 3));// 激活锚点(参数:第n个layout)glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);// 解绑VAO/VBOglBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);/****************************************************/
}std::string OpenGLClass::ReadGlslContext(const char *sPath)
{std::string strContext;if (!sPath) { return strContext; }std::ifstream sFile;sFile.open(sPath);if (sFile.is_open()){std::stringstream sStream;sStream << sFile.rdbuf();strContext = sStream.str();}return strContext;
}bool OpenGLClass::initShader(const char *_vertexPath, const char *_fragPath)
{char infoLog[512] = { 0 };int successFlag = 0;/*********************************************************/ // vertex编译std::string vertexContext = ReadGlslContext(_vertexPath); if (vertexContext.empty()) { return false; }const char *cVertexContext = vertexContext.c_str();// 创建顶点着色器对象unsigned int iVertexID = glCreateShader(GL_VERTEX_SHADER);// 为顶点着色器指定源码(参数2:传过去几个)glShaderSource(iVertexID, 1, &cVertexContext, nullptr);// 编译顶点着色器源码glCompileShader(iVertexID);// 查看编译顶点着色器源码结果glGetShaderiv(iVertexID, GL_COMPILE_STATUS, &successFlag);if (!successFlag) // 编译失败{// 获取编译失败原因glGetShaderInfoLog(iVertexID, 512, nullptr, infoLog);std::cout << "glGetShaderiv GL_VERTEX_SHADER" << iVertexID << " fail:" << infoLog << std::endl; return false;}cVertexContext = nullptr;/*********************************************************//*********************************************************/ // fragment编译std::string fragmentContext = ReadGlslContext(_fragPath); if (fragmentContext.empty()) { return false; }const char *cFragmentContext = fragmentContext.c_str();// 创建片段着色器对象unsigned int iFragmentID = glCreateShader(GL_FRAGMENT_SHADER);// 为片段着色器指定源码(参数2:传过去几个)glShaderSource(iFragmentID, 1, &cFragmentContext, nullptr);// 编译片段着色器源码glCompileShader(iFragmentID);// 查看编译片段着色器源码结果glGetShaderiv(iFragmentID, GL_COMPILE_STATUS, &successFlag);if (!successFlag) // 编译失败{// 获取编译失败原因glGetShaderInfoLog(iFragmentID, 512, nullptr, infoLog);std::cout << "glGetShaderiv GL_FRAGMENT_SHADER" << iFragmentID << " fail:" << infoLog << std::endl; return false;}cFragmentContext = nullptr;/*********************************************************//*********************************************************/ // 链接// 创建一个空的程序对象shaderProgram = glCreateProgram();if (shaderProgram == 0) { std::cout << "glCreateProgram fail!\n"; return false; }// 将着色器对象附加到程序对象上(注:glDetachShader为移除程序对象中的指定着色器对象)glAttachShader(shaderProgram, iVertexID);glAttachShader(shaderProgram, iFragmentID);// 进行链接程序对象glLinkProgram(shaderProgram);// 查看链接状态glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successFlag);if (!successFlag) // 链接失败{// 获取链接失败原因glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);std::cout << "glGetProgramiv " << shaderProgram << " fail:" << infoLog << std::endl; return false;}/*********************************************************//* 在链接完成后,将编译shader相关删除。仅留下链接ID */if (glIsShader(iVertexID)) { glDeleteShader(iVertexID); }if (glIsShader(iFragmentID)) { glDeleteShader(iFragmentID); }return true;
}
完整源码下载
源码下载
关注
Wx GZH:码农总动员
笔者 - jxd