系列六:Shader的使用
Vertex.h
1 #pragma once 2 3 #include <gl/glew.h> 4 5 //The vertex definition 6 struct Vertex 7 { 8 //This is the position struct, when you store a struct or class 9 //inside of another struct or class, it is called composition, This is 10 //layed out exactly the same in memory as if we had a float position[2], 11 //but doing it this way makes more sense. 12 13 struct Position //Position is the type 14 { 15 float x; 16 float y; 17 } position; //position is the same of this particular instance 18 19 //4 bytes for r g b a color. 20 struct Color 21 { 22 GLubyte r; 23 GLubyte g; 24 GLubyte b; 25 GLubyte a; 26 } color; 27 };
GLSLProgram.h
#pragma once #include <string> #include <gl/glew.h> class GLSLProgram { public: GLSLProgram(); ~GLSLProgram(); void compileShaders(const std::string& vertexSharderFilePath, const std::string& fragmentShaderFilePath); void linkShaders(); void addAttribute(const std::string& attributeName); void use(); void unuse(); private: void compileShader(const std::string& filePath, GLuint shaderID); GLuint m_progamID; GLuint m_vertexShaderID; GLuint m_fragmentShaderID; int m_numAttributes; };
GLSLProgram.cpp
#include "GLSLProgram.h" #include "Error.h" #include <fstream> #include <vector> GLSLProgram::GLSLProgram() :m_progamID(0), m_vertexShaderID(0), m_fragmentShaderID(0), m_numAttributes(0) { } GLSLProgram::~GLSLProgram() { } void GLSLProgram::compileShaders(const std::string& vertexSharderFilePath, const std::string& fragmentShaderFilePath) { // Get a program object. // Because addAttribute will use this programID m_progamID = glCreateProgram(); m_vertexShaderID = glCreateShader(GL_VERTEX_SHADER); if (0 == m_vertexShaderID) { faterError("Vertex shader failed to the created!"); } m_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); if (0 == m_fragmentShaderID) { faterError("Fragment shader failed to the created!"); } compileShader(vertexSharderFilePath, m_vertexShaderID); compileShader(fragmentShaderFilePath, m_fragmentShaderID); } // Now time to link them together into a program. void GLSLProgram::linkShaders() { // Attach our shaders to our program glAttachShader(m_progamID, m_vertexShaderID); glAttachShader(m_progamID, m_fragmentShaderID); // Link our program glLinkProgram(m_progamID); // Note the different functions here: glGetProgram* instead of glGetShader*. GLint isLinked(0); glGetProgramiv(m_progamID, GL_LINK_STATUS, &isLinked); if (GL_FALSE == isLinked) { GLint maxLength = 0; glGetProgramiv(m_progamID, GL_INFO_LOG_LENGTH, &maxLength); // The maxLength includes the NULL character std::vector<char> infoLog(maxLength); glGetProgramInfoLog(m_progamID, maxLength, &maxLength, &infoLog[0]); // We don't need the program anymore glDeleteProgram(m_progamID); // Don't leak shaders either glDeleteShader(m_vertexShaderID); glDeleteShader(m_fragmentShaderID); std::printf("%s\n", &(infoLog[0])); faterError("Shaders failed to link"); } // Always detach shaders after a successful link glDetachShader(m_progamID, m_vertexShaderID); glDetachShader(m_progamID, m_fragmentShaderID); // Don't leak shaders either glDeleteShader(m_vertexShaderID); glDeleteShader(m_fragmentShaderID); } void GLSLProgram::addAttribute(const std::string& attributeName) { glBindAttribLocation(m_progamID, m_numAttributes++, attributeName.c_str()); } void GLSLProgram::use() { glUseProgram(m_progamID); for (int i = 0; i < m_numAttributes; ++ i) { glEnableVertexAttribArray(i); } } void GLSLProgram::unuse() { glUseProgram(0); for (int i = 0; i < m_numAttributes; ++ i) { glDisableVertexAttribArray(i); } } void GLSLProgram::compileShader(const std::string& filePath, GLuint shaderID) { std::ifstream vertexFile(filePath); if (vertexFile.fail()) { perror(filePath.c_str()); faterError("Failed to open " + filePath); } std::string fileContents = ""; std::string line; while (std::getline(vertexFile, line)) { fileContents += line + "\n"; } vertexFile.close(); const char* contentsPtr = fileContents.c_str(); glShaderSource(shaderID, 1, &contentsPtr, nullptr); glCompileShader(shaderID); GLint isCompiled(0); glGetShaderiv(shaderID, GL_COMPILE_STATUS, &isCompiled); if (GL_FALSE == isCompiled) { GLint maxLength(0); glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxLength); std::vector<char> infoLog(maxLength); glGetShaderInfoLog(shaderID, maxLength, &maxLength, &infoLog[0]); glDeleteShader(shaderID); std::printf("%s\n", &(infoLog[0])); faterError("Shader " + filePath + " failed to compile"); } }
Sprite.cpp
#include "Sprite.h" #include "vertex.h" #include <cstddef> Sprite::Sprite() :m_X(0.0f), m_Y(0.0f), m_Width(0.0f), m_Height(0.0f), m_vboID(0) { } Sprite::~Sprite() { if (m_vboID) { glDeleteBuffers(1, &m_vboID); } } void Sprite::init(float x, float y, float width, float height) { m_X = x; m_Y = y; m_Width = width; m_Height = height; if (0 == m_vboID) { glGenBuffers(1, &m_vboID); } //Hard code, vertex num: 6, xy:2 // v2 v1 // // // v3 Vertex vertexData[6]; vertexData[0].position.x = x + width; vertexData[0].position.y = y + height; vertexData[1].position.x = x; vertexData[1].position.y = y + height; vertexData[2].position.x = x; vertexData[2].position.y = y; //Second Triangle vertexData[3].position.x = x; vertexData[3].position.y = y; vertexData[4].position.x = x + width; vertexData[4].position.y = y; vertexData[5].position.x = x + width; vertexData[5].position.y = y + width; for (int i = 0; i < 6; ++ i) { vertexData[i].color.r = 255; vertexData[i].color.g = 0; vertexData[i].color.b = 255; vertexData[i].color.a = 255; } #if 0 float vertexData[6 * 2]; //First Triangle vertexData[0] = x + width; vertexData[1] = y + height; vertexData[2] = x; vertexData[3] = y + height; vertexData[4] = x; vertexData[5] = y; //Second Triangle vertexData[6] = x; vertexData[7] = y; vertexData[8] = x + width; vertexData[9] = y; vertexData[10] = x + width; vertexData[11] = y + width; #endif vertexData[1].color.r = 0; vertexData[1].color.g = 0; vertexData[1].color.b = 255; vertexData[1].color.a = 255; vertexData[4].color.r = 0; vertexData[4].color.g = 255; vertexData[4].color.b = 0; vertexData[4].color.a = 255; glBindBuffer(GL_ARRAY_BUFFER, m_vboID); glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } void Sprite::draw() { // Bind the buffer object glBindBuffer(GL_ARRAY_BUFFER, m_vboID); // Tell OpenGL that we want to use the first // attribute array. we only need one array right // now since we are only using position glEnableVertexAttribArray(0); // This is the position attribute pointer glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position)); // This is the color attribute pointer glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color)); // Draw the 6 vertices to the screen glDrawArrays(GL_TRIANGLES, 0, 6); // Disable the vertex attrib array, This is not optional glDisableVertexAttribArray(0); // Unbind the VBO glBindBuffer(GL_ARRAY_BUFFER, 0); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix