PlayerGLWidget2.cpp 14 KB

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