PlayerGLWidget2.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include "PlayerGLWidget2.h"
  2. #include "spdlog.h"
  3. #include <QFile>
  4. #include <QTextStream>
  5. #include <cstdint>
  6. #include <cstring>
  7. #include <gl/gl.h>
  8. #include <qobject.h>
  9. #include <qopenglext.h>
  10. #include <string.h>
  11. #include <string>
  12. PlayerGLWidget2::PlayerGLWidget2(QWidget *parent) : QOpenGLWidget(parent)
  13. {
  14. m_vertexCount = 4; // 顶点数量
  15. m_vertexSize = 8; // 顶点大小
  16. // m_vertices = new float[m_vertexCount * m_vertexSize] {
  17. // /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
  18. // -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 左下
  19. // 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // 右下
  20. // 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  21. // -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // 右上
  22. // };
  23. m_vertices = new float[m_vertexCount * m_vertexSize] {
  24. /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
  25. -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 左下
  26. 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // 右下
  27. 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  28. -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // 右上
  29. };
  30. m_indexCount = 6; // 索引数量
  31. m_indices = new uint32_t[m_indexCount] {
  32. 0, 1, 2, // 第一个三角形
  33. 2, 3, 0 // 第二个三角形
  34. };
  35. /* 打开着色器代码 */
  36. QString vertexShaderFile = ":/shader/vertexShader.glsl";
  37. if (!loadShaderCode(vertexShaderFile, &m_vertexShaderCode)) {
  38. return;
  39. }
  40. // SPDLOG_INFO("顶点着色器代码: \n{}", m_vertexShaderCode);
  41. QString fragmentShaderFile = ":/shader/fragmentShader.glsl";
  42. if (!loadShaderCode(fragmentShaderFile, &m_fragmentShaderCode)) {
  43. return;
  44. }
  45. // SPDLOG_INFO("片段着色器代码: \n{}", m_fragmentShaderCode);
  46. /* 加载问了图片 */
  47. QString imageFile = ":/Image/image/1.jpg";
  48. if (!loadImage(imageFile, m_imageTexture)) {
  49. return;
  50. }
  51. QString imageFile2 = ":/Image/image/awesomeface.png";
  52. if (!loadImage(imageFile2, m_imageTexture2)) {
  53. return;
  54. }
  55. }
  56. PlayerGLWidget2::~PlayerGLWidget2()
  57. {
  58. if(m_vertices != nullptr)
  59. {
  60. delete[] m_vertices;
  61. m_vertices = nullptr;
  62. }
  63. if(m_indices != nullptr)
  64. {
  65. delete[] m_indices;
  66. m_indices = nullptr;
  67. }
  68. if(m_vertexShaderCode != nullptr)
  69. {
  70. delete[] m_vertexShaderCode;
  71. m_vertexShaderCode = nullptr;
  72. }
  73. if(m_fragmentShaderCode != nullptr)
  74. {
  75. delete[] m_fragmentShaderCode;
  76. m_fragmentShaderCode = nullptr;
  77. }
  78. }
  79. void PlayerGLWidget2::initializeGL()
  80. {
  81. /* 初始化OpenGL函数 */
  82. initializeOpenGLFunctions();
  83. /* -------------------------------------------------------------------------------------
  84. * 顶点数组对象
  85. * ------------------------------------------------------------------------------------ */
  86. glGenVertexArrays(1, &m_VAO1); // 生成一个VAO,返回的ID存储在VAO1中
  87. glBindVertexArray(m_VAO1); // 绑定VAO
  88. /* -------------------------------------------------------------------------------------
  89. * 创建顶点数组缓冲区
  90. * ------------------------------------------------------------------------------------ */
  91. glGenBuffers(1, &m_VBO1);
  92. glBindBuffer(GL_ARRAY_BUFFER, m_VBO1); // 绑定VBO
  93. glBufferData(GL_ARRAY_BUFFER, m_vertexCount * m_vertexSize * sizeof(float), m_vertices, GL_STATIC_DRAW);
  94. /* -------------------------------------------------------------------------------------
  95. * 创建EBO
  96. * ------------------------------------------------------------------------------------ */
  97. glGenBuffers(1, &m_EBO1);
  98. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO1);
  99. glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(uint32_t), m_indices, GL_STATIC_DRAW); // 绑定EBO
  100. /* -------------------------------------------------------------------------------------
  101. * 链接顶点属性
  102. * ------------------------------------------------------------------------------------ */
  103. // 设置顶点属性指针,告诉OpenGL如何解析顶点数据
  104. glVertexAttribPointer(
  105. 0, /* 顶点属性位置,0表示第一个属性 */
  106. 3, /* 每个顶点属性的大小,这里是3,表示x、y、z坐标 */
  107. GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
  108. m_vertexSize * sizeof(float), /* 步长,表示每个顶点属性之间的间隔 */
  109. (void*)0 /* 偏移量,表示该属性(顶点坐标)从第0个字节开始 */
  110. );
  111. /* 启用顶点属性 */
  112. glEnableVertexAttribArray(0);
  113. // 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔8个字节
  114. glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, m_vertexSize * sizeof(float), (void*)(3*sizeof(float)));
  115. glEnableVertexAttribArray(1);
  116. /* 设置纹理位置 */
  117. glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, m_vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
  118. glEnableVertexAttribArray(2); // 启用纹理坐标属性
  119. /* -------------------------------------------------------------------------------------
  120. * 纹理对象
  121. * ------------------------------------------------------------------------------------ */
  122. glGenTextures(1, &m_texture1); // 生成纹理对象
  123. glBindTexture(GL_TEXTURE_2D, m_texture1); // 绑定纹理对象
  124. /* 设置当前绑定的纹理对象的环绕、过滤方式 */
  125. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // S轴环绕方式
  126. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // T轴环绕方式
  127. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // 纹理缩小过滤方式
  128. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 纹理放大过滤方式
  129. /* 纹理数据,最后一个参数是纹理数据的指针,0表示数据在当前上下文中 */
  130. /* 纹理数据,最后一个参数是纹理数据的指针 */
  131. glTexImage2D(
  132. GL_TEXTURE_2D,
  133. 0, // Mipmap 级别
  134. GL_RGBA, // 纹理内部格式
  135. m_imageTexture.width(), // 纹理宽度
  136. m_imageTexture.height(), // 纹理高度
  137. 0, // 边框(必须为 0)
  138. GL_RGBA, // 数据格式(与 QImage 格式匹配)
  139. GL_UNSIGNED_BYTE, // 数据类型
  140. m_imageTexture.bits() // 数据指针
  141. );
  142. glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理
  143. glGenTextures(1, &m_texture2); // 生成纹理对象
  144. glBindTexture(GL_TEXTURE_2D, m_texture2); // 绑定纹理对象
  145. /* 设置当前绑定的纹理对象的环绕、过滤方式 */
  146. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // S轴环绕方式
  147. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // T轴环绕方式
  148. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // 纹理缩小过滤方式
  149. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 纹理放大过滤方式
  150. /* 纹理数据,最后一个参数是纹理数据的指针,0表示数据在当前上下文中 */
  151. /* 纹理数据,最后一个参数是纹理数据的指针 */
  152. glTexImage2D(
  153. GL_TEXTURE_2D,
  154. 0, // Mipmap 级别
  155. GL_RGBA, // 纹理内部格式
  156. m_imageTexture2.width(), // 纹理宽度
  157. m_imageTexture2.height(), // 纹理高度
  158. 0, // 边框(必须为 0)
  159. GL_RGBA, // 数据格式(与 QImage 格式匹配)
  160. GL_UNSIGNED_BYTE, // 数据类型
  161. m_imageTexture2.bits() // 数据指针
  162. );
  163. glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理
  164. /* -------------------------------------------------------------------------------------
  165. * 着色器程序对象
  166. * ------------------------------------------------------------------------------------ */
  167. /* 编译顶点着色器 */
  168. GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  169. /* 着色器代码 */
  170. glShaderSource(vertexShader, 1, &m_vertexShaderCode, nullptr);
  171. glCompileShader(vertexShader); // 编译着色器
  172. /* 检查编译错误 */
  173. GLint success;
  174. GLchar infoLog[512];
  175. glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
  176. if(success == GL_FALSE)
  177. {
  178. glGetShaderInfoLog(vertexShader, sizeof(infoLog), nullptr, infoLog);
  179. SPDLOG_ERROR("顶点着色器编译错误: {}", infoLog);
  180. }
  181. /* 编译片段着色器 */
  182. GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  183. /* 加载着色器代码 */
  184. glShaderSource(fragmentShader, 1, &m_fragmentShaderCode, nullptr);
  185. glCompileShader(fragmentShader); // 编译着色器
  186. /* 检查编译错误 */
  187. success = 0;
  188. memset(infoLog, 0, sizeof(infoLog)); // 清空infoLog
  189. glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
  190. if(success == GL_FALSE)
  191. {
  192. glGetShaderInfoLog(fragmentShader, sizeof(infoLog), nullptr, infoLog);
  193. SPDLOG_ERROR("片段着色器编译错误: {}", infoLog);
  194. }
  195. /* 创建一个着色器程序对象 */
  196. m_shaderProgram = glCreateProgram();
  197. /* 将顶点着色器和片段着色器附加到着色器程序对象上 */
  198. glAttachShader(m_shaderProgram, vertexShader);
  199. glAttachShader(m_shaderProgram, fragmentShader);
  200. /* 链接着色器程序 */
  201. glLinkProgram(m_shaderProgram);
  202. /* 检查链接错误 */
  203. success = 0;
  204. memset(infoLog, 0, sizeof(infoLog)); // 清空infoLog
  205. glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &success);
  206. if(success == GL_FALSE)
  207. {
  208. glGetProgramInfoLog(m_shaderProgram, sizeof(infoLog), nullptr, infoLog);
  209. SPDLOG_ERROR("着色器链接错误: {}", infoLog);
  210. }
  211. /* 删除着色器对象 */
  212. glDeleteShader(vertexShader);
  213. glDeleteShader(fragmentShader);
  214. /* 解绑VAO */
  215. // glBindVertexArray(0); // 解绑VAO
  216. /* 解绑VBO */
  217. glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑VBO
  218. /* 解绑EBO */
  219. // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑EBO
  220. /* 解绑纹理对象 */
  221. // glBindTexture(GL_TEXTURE_2D, 0); // 解绑纹理对象
  222. /* 解绑着色器程序对象 */
  223. // glUseProgram(0); // 解绑着色器程序对象
  224. /* 指定纹理对象名称 */
  225. glUseProgram(m_shaderProgram); // 使用着色器程序对象
  226. }
  227. void PlayerGLWidget2::resizeGL(int w, int h)
  228. {
  229. glViewport(0, 0, w, h); // 设置视口大小
  230. }
  231. void PlayerGLWidget2::paintGL()
  232. {
  233. glClearColor(0.1f, 0.3f, 0.3f, 1.0f);
  234. glClear(GL_COLOR_BUFFER_BIT);
  235. /* 激活着色器程序对象 */
  236. glUseProgram(m_shaderProgram);
  237. /* 设置纹理单元,0表示第一个纹理单元,1表示第二个纹理单元 */
  238. glUniform1i(glGetUniformLocation(m_shaderProgram, "ourTexture1"), 0); // 纹理单元0
  239. glUniform1i(glGetUniformLocation(m_shaderProgram, "ourTexture2"), 1); // 纹理单元1
  240. /* 激活纹理单元 */
  241. glActiveTexture(GL_TEXTURE0);
  242. glBindTexture(GL_TEXTURE_2D, m_texture1); // 绑定纹理对象
  243. glActiveTexture(GL_TEXTURE1);
  244. glBindTexture(GL_TEXTURE_2D, m_texture1); // 绑定纹理对象
  245. /* 绑定VAO,绘制图形 */
  246. glBindVertexArray(m_VAO1); // 绑定VAO
  247. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形
  248. glBindVertexArray(0); // 解绑VAO
  249. }
  250. /**
  251. * @brief 打开GLSL文件,读取着色器代码
  252. *
  253. * @param fileName
  254. * @param shaderCode 取出的着色器代码,函数内部会分配内存,需要在使用完后释放
  255. * @return true
  256. * @return false
  257. */
  258. bool PlayerGLWidget2::loadShaderCode(const QString &fileName, char** shaderCode)
  259. {
  260. if(*shaderCode != nullptr) {
  261. delete[] *shaderCode;
  262. *shaderCode = nullptr;
  263. }
  264. /* 打开文件 */
  265. QFile file(fileName);
  266. if (!file.open(QIODevice::ReadOnly)) {
  267. SPDLOG_ERROR("Failed to open shader file: {}", fileName.toStdString());
  268. return false;
  269. }
  270. QByteArray ba = file.readAll();
  271. file.close();
  272. // SPDLOG_DEBUG("Shader file content: \n{}", ba.toStdString());
  273. if (ba.isEmpty()) {
  274. SPDLOG_ERROR("Shader file is empty: {}", fileName.toStdString());
  275. return false;
  276. }
  277. /* 计算字符串长度 */
  278. int len = ba.length() + 1; // +1是为了'\0'结尾
  279. /* 分配内存 */
  280. *shaderCode = new char[len];
  281. /* 复制字符串 */
  282. strcpy_s(*shaderCode, len, ba.toStdString().c_str());
  283. return true;
  284. }
  285. /* 加载图片 */
  286. bool PlayerGLWidget2::loadImage(const QString &fileName, QImage &imageTexture)
  287. {
  288. imageTexture.load(fileName);
  289. if (imageTexture.isNull()) {
  290. SPDLOG_ERROR("Failed to load image: {}", fileName.toStdString());
  291. return false;
  292. }
  293. /* 翻转图片,OpenGL的坐标系和Qt的坐标系是相反的,所以需要翻转图片 */
  294. // imageTexture = imageTexture.mirrored(false, true);
  295. // if (imageTexture.isNull()) {
  296. // SPDLOG_ERROR("Failed to flip image: {}", fileName.toStdString());
  297. // return false;
  298. // }
  299. /* 将图片转换为RGBA格式 */
  300. imageTexture = imageTexture.convertToFormat(QImage::Format_RGBA8888);
  301. if (imageTexture.isNull()) {
  302. SPDLOG_ERROR("Failed to convert image to RGBA format: {}", fileName.toStdString());
  303. return false;
  304. }
  305. return true;
  306. }