OpenGL笔记<第一章> 构建 GLSL class
恭喜,我们终于很扎实地完成了第一章——glsl 入门
不幸的是,it's not the basic of GLSL shader ,我们下一节开篇,basic of GLSL shader
在下一章开篇之前,我们先来把我们第一章学到的东西封装一下,大家应该能够体会到,很多东西都是固定的模块,所以,为了进一步的盖高楼,我们把根基技术包装为一个产品,之后我们就不重复做根基的制作了。
更不幸的是,看了下第二章第一节:
漫反射环,什么光强表面辐射啊,光反射啊,线性代数吖,虽然对于学院派公式不是很头疼,但是其中的流程细节对图像的形成产生的影响还需要整几天,写完这篇就滚去研究啦。
废话不多说嘞,我们今天要把之前所学的一些模块封装成一个完整的类,以便使用,天天调用宏是不是手很累嘞,虽然这样做能把握很多细节,但是为了快速开发,还是需要封装一下子。
周一课比较多,只好大晚上才来更新,不好意思要晚一天了
///////////////////////////////////////// 更新分割线 //////////////////////////////////
我们封装一个类,依旧是需要拿一个例子来检测这个类的正确性,我们依旧选择第四节的旋转三角形来测验,其实哪个都无所谓啦,我们主要封装几个类使我们的编程更方便一点。
我们所做的也可以理解成是一个方便开发的小小型类库
构架设计
我们需要一个窗口类,使得内部自动完成一些状态的设置,比如一些常用的:开启双缓存,开启深度测试,开启RGBA模式等等,还有一些初始化窗口的操作等等一系列重复性动作,我们让他们在类中自动完成。
当我们创建一个窗口时,我们只需要传入一些窗口的特征:大小,标题,等。
它还包括渲染过程的控制,窗口的建立和消亡,外部相应等。
我们需要一个开发设计类,让我们的开发人员只需写一个类即可,写好之后,传入到另外一个接口中,系统即可自动完成。
我们需要一个底层glsl类,它用来处理着色器的编译连接使用,以及错误异常机制的处理,以及提供一些常用的底层接口,比如:
任一枚举类型的字符串数据(意思是,如果我们调用opengl API的时候,接受一个返回的枚举参数,我们需要知道它的字符串信息,我们需要一个接口去做);
还有设置uniform数据信息等。
实现
我们一直都提倡,先看效果,再讲述过程,今天所述的不是效果,是一个小小型类库设计,所以我们展示它的运作形式。
我们现在可能是个精简版,功能不是很全可能有些地方不是很合理,这里只提供作一种思想方式。
原来准备整成网盘资料分享的,后来想想,还是放在这里吧
底层glsl类
#ifndef _GLSLPROGRAM_H
#define _GLSLPROGRAM_H #include <glad/glad.h>
#include <stdexcept>
#include <string>
#include <map>
#include <glm\glm.hpp> class GLSLException : public std::runtime_error
{
public:
GLSLException(const std::string& msg)
:std::runtime_error(msg) { }
}; class GLSLProgram
{
public:
GLSLProgram();
GLSLProgram(const GLSLProgram&) = delete; //forbid copying the object of class
GLSLProgram& operator=(const GLSLProgram& rhs) = delete;
~GLSLProgram(); void compileShader(const GLchar* filename,
GLenum type) throw(GLSLException);
void compileShader(const std::string& source,
GLenum type,
const GLchar* filename = nullptr) throw(GLSLException);
void link() /* 连接程序 */ throw(GLSLException);
void use() /* 使用程序 */ throw(GLSLException);
void validate() /* 功能详解见 cpp */ throw(GLSLException); GLint getHandle()const;
GLboolean isLinked()const;
void printActiveUniform()const;
void printActiveAttribs()const;
void printActiveUniformBlocks()const;
const GLchar* _stringOftype(GLenum type)const; void BindAttribLoc(GLuint location, const GLchar* name); //我们只写uniform variable 设置相关的函数,ubo
//关于vert Attributes,属于vbo,因不同程序而异,另做处理,或者读者自行添加
void setUniform(const GLchar* name, GLint val);
void setUniform(const GLchar* name, GLuint val);
void setUniform(const GLchar* name, GLfloat val);
void setUniform(const GLchar* name, GLboolean val);
void setUniform(const GLchar* name, const glm::vec2 & v);
void setUniform(const GLchar* name, const glm::vec3 & v);
void setUniform(const GLchar* name, const glm::vec4 & v);
void setUniform(const GLchar* name, const glm::mat4 & m);
void setUniform(const GLchar* name, const glm::mat3 & m);
void setUniform(const GLchar* name, GLfloat x, GLfloat y, GLfloat z); private:
GLint _handle;
GLboolean _linked;
std::map<std::string, GLint> _uniformLocations; void _initLocation();
GLint _getUniformLoc(const GLchar* name);
}; #endif //_GLSLPROGRAM_H
glsl类.h
貌似没什么说的。
就是之前几节的整合,之前都讲过
#include "glslProgram.h"
#include <fstream>
#include <sstream>
#include <iostream> // 因为其他开发者包含文件的时候值包含头文件,
// 所以我们可以大胆地cpp里面引用所有的namespace
using namespace std;
using namespace glm; GLSLProgram::GLSLProgram()
:_handle()
,_linked(GL_FALSE)
{
} GLSLProgram::~GLSLProgram()
{
if (!_handle)return; //查询有多少个shader连接在program上
GLint numShaders{ };
glGetProgramiv(_handle, GL_ATTACHED_SHADERS, &numShaders); //获取所有shader的名字,然后从程序中删除
GLuint* shaderNames = new GLuint[numShaders];
glGetAttachedShaders(_handle, numShaders, nullptr, shaderNames);
for (int i{ }; i < numShaders; ++i)
glDeleteShader(shaderNames[i]); //删除shader program
glDeleteProgram(_handle); delete[] shaderNames;
} void GLSLProgram::compileShader(const GLchar* filename, GLenum type)
{
ifstream infile(filename); if (!infile.is_open())
{
string msg = string("Shader file: ") + filename + " is failed to open";
throw GLSLException(msg);
} if (_handle <= )
{
_handle = glCreateProgram();
if (_handle <= )
throw GLSLException("Unable to create a shader program.");
} //获取内容
stringstream shadercode;
shadercode << infile.rdbuf();
infile.close(); compileShader(shadercode.str(), type, filename);
} void GLSLProgram::compileShader(const string& source, GLenum type, const GLchar* filename)
{
if (_handle <= )
{
_handle = glCreateProgram();
if (_handle <= )
throw GLSLException("Unable to create a shader program.");
} GLint shaderHandle = glCreateShader(type);
if ( == shaderHandle) //Check the state of Creating Shader
{
string msg = string(_stringOftype(type)) + " Shader program is failed to create.";
throw GLSLException("msg");
} const GLchar* shaderSource = source.c_str();
const GLchar* codeArray[]{ shaderSource };
glShaderSource(shaderHandle, , codeArray, nullptr); glCompileShader(shaderHandle); //Check the state of Compiling shader
GLint result;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &result);
if (GL_FALSE == result)
{
string msg = string{ _stringOftype(type) } +"shader compilation failed.\n"; GLint logLenth;
glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, &logLenth);
if (logLenth > )
{
GLchar* c_log = new GLchar[logLenth];
GLsizei written{ };
glGetShaderInfoLog(shaderHandle, logLenth, &written, c_log);
msg += c_log;
delete[] c_log;
}
throw GLSLException(msg);
}
else
glAttachShader(_handle, shaderHandle);
} void GLSLProgram::link()
{
if (_linked)return; if (_handle <= )
throw GLSLException("program hasn't been compiled."); glLinkProgram(_handle); GLint status{ };
glGetProgramiv(_handle, GL_LINK_STATUS, &status);
if (GL_FALSE == status)
{
string msg{ "failed to link shader program.\n" }; GLint logLength;
glGetProgramiv(_handle, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > )
{
GLchar* c_log = new GLchar[logLength]; GLsizei written;
glGetShaderInfoLog(_handle, logLength, &written, c_log); msg += c_log;
delete[] c_log;
}
throw GLSLException(msg);
}
else
{
_linked = GL_TRUE;
//因为当着色器程序连接完成之后,各个量的location值就确定了,我们顺便做一个映射
_initLocation();
}
} void GLSLProgram::use()
{
if (_handle <= || (!_linked))
throw GLSLException("Shader has not been linked.");
glUseProgram(_handle);
} GLint GLSLProgram::getHandle()const
{
return _handle;
} GLboolean GLSLProgram::isLinked()const
{
return _linked;
} void GLSLProgram::_initLocation()
{
_uniformLocations.clear(); GLint numUniforms{ };
glGetProgramInterfaceiv(_handle, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numUniforms); GLenum properties[] = { GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_BLOCK_INDEX }; for (GLint i = ; i < numUniforms; ++i) {
GLint results[];
glGetProgramResourceiv(_handle, GL_UNIFORM, i, , properties, , nullptr, results); if (results[] != -) continue; // Skip uniforms in blocks
GLint bufSize = results[] + ;
GLchar * name = new GLchar[bufSize];
glGetProgramResourceName(_handle, GL_UNIFORM, i, bufSize, nullptr, name);
_uniformLocations[name] = results[];
delete[] name;
}
} GLint GLSLProgram::_getUniformLoc(const GLchar* name)
{
auto pos = _uniformLocations.find(name); if (pos == _uniformLocations.end()) {
_uniformLocations[name] = glGetUniformLocation(_handle, name);
}
return _uniformLocations[name];
} void GLSLProgram::printActiveUniform()const
{
GLint numUniforms{ };
glGetProgramInterfaceiv(_handle, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numUniforms); GLenum properties[] = { GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_BLOCK_INDEX }; cout << "Active uniforms:" << endl;
for (int i = ; i < numUniforms; ++i) {
GLint results[];
glGetProgramResourceiv(_handle, GL_UNIFORM, i, , properties, , nullptr, results); if (results[] != -) continue; // Skip uniforms in blocks
GLint bufSize = results[] + ;
char * name = new char[bufSize];
glGetProgramResourceName(_handle, GL_UNIFORM, i, bufSize, nullptr, name);
cout << "Location: " << results[] << " " << name << " (" << _stringOftype(results[]) << ") " << endl;
delete[] name;
}
} void GLSLProgram::printActiveAttribs()const
{
GLint numAttribs;
glGetProgramInterfaceiv(_handle, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &numAttribs); GLenum properties[] = { GL_NAME_LENGTH, GL_TYPE, GL_LOCATION }; cout << "Active attributes:" << endl;
for (int i = ; i < numAttribs; ++i) {
GLint results[];
glGetProgramResourceiv(_handle, GL_PROGRAM_INPUT, i, , properties, , nullptr, results); GLint bufSize = results[] + ;
char * name = new char[bufSize];
glGetProgramResourceName(_handle, GL_PROGRAM_INPUT, i, bufSize, nullptr, name);
cout << "Location: " << results[] << " " << name << " (" << _stringOftype(results[]) << ") " << endl;
delete[] name;
}
} void GLSLProgram::printActiveUniformBlocks()const
{
GLint numBlocks{ }; glGetProgramInterfaceiv(_handle, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numBlocks);
GLenum blockProps[] = { GL_NUM_ACTIVE_VARIABLES, GL_NAME_LENGTH };
GLenum blockIndex[] = { GL_ACTIVE_VARIABLES };
GLenum props[] = { GL_NAME_LENGTH, GL_TYPE, GL_BLOCK_INDEX }; for (int block = ; block < numBlocks; ++block) {
GLint blockInfo[];
glGetProgramResourceiv(_handle, GL_UNIFORM_BLOCK, block, , blockProps, , nullptr, blockInfo);
GLint numUnis = blockInfo[]; GLchar * blockName = new GLchar[blockInfo[] + ];
glGetProgramResourceName(_handle, GL_UNIFORM_BLOCK, block, blockInfo[] + , nullptr, blockName);
cout << R"+(Uniform block ")+" << blockName << R"+(" : )+" << endl; delete[] blockName; GLint * unifIndexes = new GLint[numUnis];
glGetProgramResourceiv(_handle, GL_UNIFORM_BLOCK, block, , blockIndex, numUnis, nullptr, unifIndexes); for (int unif = ; unif < numUnis; ++unif) {
GLint uniIndex = unifIndexes[unif];
GLint results[];
glGetProgramResourceiv(_handle, GL_UNIFORM, uniIndex, , props, , nullptr, results); GLint bufSize = results[] + ;
GLchar * name = new GLchar[bufSize];
glGetProgramResourceName(_handle, GL_UNIFORM, uniIndex, bufSize, nullptr, name);
cout << " " << name << "(" << _stringOftype(results[]) << ")" << endl;
delete[] name;
}
delete[] unifIndexes;
}
} void GLSLProgram::BindAttribLoc(GLuint location, const GLchar* name)
{
glBindAttribLocation(_handle, location, name);
} const GLchar* GLSLProgram::_stringOftype(GLenum type)const
{
switch (type)
{
//shader enum
case GL_VERTEX_SHADER: return "vertex";
case GL_FRAGMENT_SHADER: return "fragment";
case GL_GEOMETRY_SHADER: return "geometry";
case GL_TESS_CONTROL_SHADER: return "tess_control";
case GL_TESS_EVALUATION_SHADER: return "tess_evaluation";
case GL_COMPUTE_SHADER: return "compute"; //data enum
case GL_FLOAT: return "float";
case GL_FLOAT_VEC2: return "fvec2";
case GL_FLOAT_VEC3: return "fvec3";
case GL_FLOAT_VEC4: return "fvec4";
case GL_FLOAT_MAT2: return "fmat2";
case GL_FLOAT_MAT2x3: return "fmat2*3";
case GL_FLOAT_MAT2x4: return "fmat2*4";
case GL_FLOAT_MAT3: return "fmat3";
case GL_FLOAT_MAT3x2: return "fmat3*2";
case GL_FLOAT_MAT3x4: return "fmat3*4";
case GL_FLOAT_MAT4: return "fmat4";
case GL_FLOAT_MAT4x2: return "fmat4*2";
case GL_FLOAT_MAT4x3: return "fmat4*3"; case GL_DOUBLE: return "double";
case GL_DOUBLE_VEC2: return "lfvec2";
case GL_DOUBLE_VEC3: return "lfvec3";
case GL_DOUBLE_VEC4: return "lfvec4";
case GL_DOUBLE_MAT2: return "lfmat2";
case GL_DOUBLE_MAT2x3: return "lfmat2*3";
case GL_DOUBLE_MAT2x4: return "lfmat2*4";
case GL_DOUBLE_MAT3: return "lfmat3";
case GL_DOUBLE_MAT3x2: return "lfmat3*2";
case GL_DOUBLE_MAT3x4: return "lfmat3*4";
case GL_DOUBLE_MAT4: return "lfmat4";
case GL_DOUBLE_MAT4x2: return "lfmat4*2";
case GL_DOUBLE_MAT4x3: return "lfmat4*3"; case GL_INT: return "int";
case GL_INT_VEC2: return "int_vec2";
case GL_INT_VEC3: return "int_vec3";
case GL_INT_VEC4: return "int_vec4"; case GL_UNSIGNED_BYTE: return "unsignedByte";
case GL_UNSIGNED_INT: return "unsignedInt";
case GL_BOOL: return "bool"; default: return "?";
}
} void GLSLProgram::validate()
/* 验证程序
** 首先,它会检查程序是否可执行
** 此函数一般用于程序开发阶段,验证过程产生的信息会被存储在program日志中
** 当渲染程序发布后,并且当可编程着色器是当前状态的一部分时,OpenGL实现必须进行的验证操作。
** 当当前程序对象中的任何两个活动样品是不同类型但是指向相同纹理图像单元时,
** 函数glDrawArrays和glDrawElements会产生GL_INVALID_OPERATION错误。
** 当渲染程序发布后,程序很难捕获这些错误,即使能,也会大大降低效率。
** 所以,我们建议程序在开发阶段调用glValidateProgram函数检测这些问题。
*/
{
if (!_linked)
throw GLSLException("Program isn't linked."); GLint status;
glValidateProgram(_handle);
glGetProgramiv(_handle, GL_VALIDATE_STATUS, &status); if (GL_FALSE == status) {
// Store log and return false
GLint length{ };
string msg{ "Program failed to validate\n" }; glGetProgramiv(_handle, GL_INFO_LOG_LENGTH, &length); if (length > ) {
GLchar *c_log = new GLchar[length];
GLint written{ };
glGetProgramInfoLog(_handle, length, &written, c_log);
msg += c_log;
delete[] c_log;
}
throw GLSLException(msg);
}
} void GLSLProgram::setUniform(const GLchar* name, GLint val)
{
glUniform1i(_getUniformLoc(name), val);
} void GLSLProgram::setUniform(const GLchar* name, GLuint val)
{
glUniform1ui(_getUniformLoc(name), val); } void GLSLProgram::setUniform(const GLchar* name, GLfloat val)
{
glUniform1f(_getUniformLoc(name), val);
} void GLSLProgram::setUniform(const GLchar* name, GLboolean val)
{
setUniform(name, (GLuint)val);
} void GLSLProgram::setUniform(const GLchar* name, const glm::vec2 & v)
{
glUniform2f(_getUniformLoc(name), v.x, v.y); } void GLSLProgram::setUniform(const GLchar* name, const glm::vec3 & v)
{
glUniform3f(_getUniformLoc(name), v.x, v.y, v.z); } void GLSLProgram::setUniform(const GLchar* name, const glm::vec4 & v)
{
glUniform4f(_getUniformLoc(name), v.x, v.y, v.z, v.w); } void GLSLProgram::setUniform(const GLchar* name, const glm::mat4 & m)
{
glUniformMatrix4fv(_getUniformLoc(name), , GL_FALSE, &m[][]);
} void GLSLProgram::setUniform(const GLchar* name, const glm::mat3 & m)
{
glUniformMatrix3fv(_getUniformLoc(name), , GL_FALSE, &m[][]);
} void GLSLProgram::setUniform(const GLchar* name, GLfloat x, GLfloat y, GLfloat z)
{
setUniform(name, vec3{ x,y,z });
}
glsl类.cpp
窗口
#ifndef _RUNNER_
#define _RUNNER_
#include "uniformExample.h"
#include <GLFW\glfw3.h>
#include <map>
#include <string> #define widthWIN 1024
#define heightWIN 768 class WinRunner
{
public:
WinRunner(const std::string& windowTitle, const int width = widthWIN, const int height = heightWIN)
{
//Initialize the GLFW
if (!glfwInit()) exit(EXIT_FAILURE); // set the version of OpenGL to 4.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, ); //一些窗口的属性
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); //可改变大小
glfwWindowHint(GLFW_DECORATED, GL_TRUE); //有标题栏和边框
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
//..还有很多属性,可按需求添加 //创建窗口
_window = glfwCreateWindow(widthWIN, heightWIN, windowTitle.c_str(), NULL, NULL);
if (!_window)
{
glfwTerminate(); //终止窗口程序,除去前缀单词可查
exit(EXIT_FAILURE);
} glfwMakeContextCurrent(_window); //将当前窗口设置为当前上下文(渲染环境)
glfwGetFramebufferSize(_window, &_win_width, &_win_height);
if (!gladLoadGL()) { exit(-); } //加载glad glClearColor(0.5f, 0.5f, 0.5f, 1.0f); //Debug信息
glDebugMessageCallback(debugCallback, NULL);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, , NULL, GL_TRUE);
glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, ,
GL_DEBUG_SEVERITY_NOTIFICATION, -, "Start debugging");
}
int run(uniform_Example& win)
{
win.init();
win.resize(_win_width, _win_height);
mainLoop(win);
glfwTerminate();
return EXIT_SUCCESS;
} private:
GLFWwindow* _window;
GLint _win_width, _win_height; void mainLoop(uniform_Example & win)
{
while (!glfwWindowShouldClose(_window) && !glfwGetKey(_window, GLFW_KEY_ESCAPE))
{
win.update(GLfloat(glfwGetTime()));
win.render();
glfwSwapBuffers(_window);// glfw下的双缓存转换
glfwPollEvents(); // Waits until events are queued and processes them
}
} static void APIENTRY debugCallback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar * msg, const void * param)
{
std::string sourceStr;
switch (source)
{
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
sourceStr = "WindowSys";
break;
case GL_DEBUG_SOURCE_APPLICATION:
sourceStr = "App";
break;
case GL_DEBUG_SOURCE_API:
sourceStr = "OpenGL";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
sourceStr = "ShaderCompiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
sourceStr = "3rdParty";
break;
case GL_DEBUG_SOURCE_OTHER:
sourceStr = "Other";
break;
default:
sourceStr = "Unknown";
} std::string typeStr;
switch (type)
{
case GL_DEBUG_TYPE_ERROR:
typeStr = "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
typeStr = "Deprecated";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
typeStr = "Undefined";
break;
case GL_DEBUG_TYPE_PORTABILITY:
typeStr = "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
typeStr = "Performance";
break;
case GL_DEBUG_TYPE_MARKER:
typeStr = "Marker";
break;
case GL_DEBUG_TYPE_PUSH_GROUP:
typeStr = "PushGrp";
break;
case GL_DEBUG_TYPE_POP_GROUP:
typeStr = "PopGrp";
break;
case GL_DEBUG_TYPE_OTHER:
typeStr = "Other";
break;
default:
typeStr = "Unknown";
} std::string sevStr;
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
sevStr = "HIGH";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
sevStr = "MED";
break;
case GL_DEBUG_SEVERITY_LOW:
sevStr = "LOW";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
sevStr = "NOTIFY";
break;
default:
sevStr = "UNK";
} printf("%s:%s[%s](%d): %s\n", sourceStr.c_str(), typeStr.c_str(), sevStr.c_str(),
id, msg);
}
}; #endif
WinRunner.h
emmm,GLUT库已经很久不更新维护了,会出现很多不便,我们用最新的GLFW库,而且GLFW也有很多学习资源,是目前很流行的一个库,所以,我们也与时俱进。
相关配置:https://blog.csdn.net/qq_37338983/article/details/78997179
再也不需要我们最开始那一节讲的那么麻烦了,也再也不用在程序最前面加一大段配置代码了,照着上面流程走一遍就都可以了,很方便,也不会出现GLUT库使用的时候一些库文件包含问题,最主要的是GLFW中关于窗口的动作和渲染过程都是可见可控的,显而易见,GLFW并没有GLUT中的loop循环回调函数,而是自己写的while循环,关于两者的优劣,在此处不做争辩。
而且GLFW库中所有的函数不仅提示参数而且还会提示函数功能简述
所以,还是很好的,很方便的。
相关的解释也都有,关于函数的作用,把前缀抹去,单词是可查的。
设计开发类
#ifndef _UNIFORM_EXAMPLE_H
#define _UNIFORM_EXAMPLE_H #include "glslProgram.h" class uniform_Example
{
public:
uniform_Example(); void compileLink(const GLchar** filenamePtr, const GLint arraySize, const GLenum* typePtr);
/*@brief 用于编译连接使用着色器
@param 参数采用类似于OpenGL的参数机制,第一个传入含有所有要编译的着色器文件的名字的数组地址
@param 第二个参数为param1所指数组的大小
@param 第三个参数为每个文件代表的着色器类型 */ void init();
void update(const GLfloat t);
void render();
void resize(const GLfloat w, const GLfloat h); private:
GLuint vaoHandle;
GLSLProgram pro;
GLfloat angle;
GLfloat win_width;
GLfloat win_height;
glm::mat4 rotationMatrix; }; #endif //_UNIFORM_EXAMPLE_H
uniformExample.h
这就是第四节中我们讲的那个旋转三角形,只不过用类的形式写了一下
main函数
#include "WinRunner.h" int main(int argc, char** argv)
{
WinRunner win{ "rotated triangle",, };
uniform_Example exam; const GLchar* filenames[]{ "basic.vert" ,"basic.frag" };
GLenum types[]{ GL_VERTEX_SHADER ,GL_FRAGMENT_SHADER }; exam.compileLink(&filenames[], , types); win.run(exam);
}
关于编译连接函数的参数设计在glslprogram中有介绍,按照opengl 宏函数参数设计习惯写的。
End
上述就是我们的小型类库设计。
当然,会有一些设计上面的不足,但目前看来还可以。
改进
按照面向对象的程序设计方法学,类的设计是为了各个模块开发的独立性,但,貌似我们的类有着莫大的联系。
我们的WinRunner中需要有程序设计开发人员的类对象,这就使得,窗口类需要依赖程序设计人员的类,而程序设计人员设计完成之后还要去改动窗口类。
当然,这是可以规避的,不然,C++岂不是白学了!!
只是时间关系,没有整。
我们可以把程序设计开发类抽象出一个基类,程序开发设计的类继承之,将常用的接口抽象出去。
而在WinRunner中只需要有基类的对象即可,和开发设计类之间的交互接口参数为基类的引用即可,它可以接受任意开发设计派生出的类
就此,WinRunner完全独立于程序开发设计类了,当然我们上面那个只是为了演示这个类系统,而并没有做抽象,而是直接在WinRunner的数据成员中创建了一个开发设计类的对象,貌似比较糟糕,很不独立,哈哈,你们改了就可以了。
到这里,我们就真的,把第一章画上了一个完美的句号。
感谢您的支持,生活愉快~
OpenGL笔记<第一章> 构建 GLSL class的更多相关文章
- C++ Primer 笔记 第一章
C++ Primer 学习笔记 第一章 快速入门 1.1 main函数 系统通过调用main函数来执行程序,并通过main函数的返回值确定程序是否成功执行完毕.通常返回0值表明程序成功执行完毕: ma ...
- Android开发艺术探索笔记——第一章:Activity的生命周期和启动模式
Android开发艺术探索笔记--第一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的第一章,主席还是把Activ ...
- Android群英传笔记——第一章:Android体系与系统架构
Android群英传笔记--第一章:Android体系与系统架构 图片都是摘抄自网络 今天确实挺忙的,不过把第一章的笔记做一下还是可以的,嘿嘿 1.1 Google的生态圈 还是得从Android的起 ...
- 《css3实战》读书笔记 第一章 基于CSS需求而编写的HTML.
笔记说明 <CSS3实战手册第3版(影印版)>可以消除Web设计工作的痛苦,并且带给你:HTML--重新入门.如果你是HTML新手,你会学到如何以CSS友好的方式进行基本页面构造.若你是H ...
- .net架构设计读书笔记--第一章 基础
第一章 基础 第一节 软件架构与软件架构师 简单的说软件架构即是为客户构建一个软件系统.架构师随便软件架构应运而生,架构师是一个角色. 2000年9月ANSI和IEEE发布了<密集性软件架构建 ...
- 《JavaScript高级程序设计》笔记——第一章到第三章
2019年,新年伊始,我打算好好重读一下<JavaScript高级程序设计>这本前端必备经典书.每天半小时. 以下内容摘自<JavaScript高级程序设计> 2019-2-1 ...
- Unity 黑暗之光 笔记 第一章
第一章 设计游戏开始进入场景 1.设置相机视野同步 选中要调整的相机 GameObject - Align With View(快捷键 Ctrl + Shift + F)
- Getting Started With Hazelcast 读书笔记(第一章)
第一章:数据集群的演化与 早期的服务器架构 显然,应用是可扩展的,但是由于是集中式服务器,随着数据库性能达到极限,再想扩展就变得极端困难,于是出现了缓存. 缓存显然再次提升了可扩展性,减轻了数据 ...
- Java学习笔记 第一章 入门<转>
第一章 JAVA入门 一.基础常识 1.软件开发 什么是软件? 软件:一系列按照特定顺序组织的计算机数据和指令的集合 系统软件:DOS,Windows,Linux 应用软件:扫雷.QQ.迅雷 什么是开 ...
随机推荐
- 好的MongoDB学习文章链接
1.MongoDB 极简实践入门 2.MongoDB中文社区 3.极客学院Mongodb 教程
- hdu 确定比赛名次(拓扑排序)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285 确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) ...
- [转]激活函数ReLU、Leaky ReLU、PReLU和RReLU
“激活函数”能分成两类——“饱和激活函数”和“非饱和激活函数”. sigmoid和tanh是“饱和激活函数”,而ReLU及其变体则是“非饱和激活函数”.使用“非饱和激活函数”的优势在于两点: 1 ...
- meterpreter使用
1.基本命令 background:将meterpreter终端隐藏在后台 sessions:查看已经成功获取的会话,想继续与某会话进行交互使用sessions –i quit:直接关闭当前meter ...
- Kettle进行数据迁移(ETL)
由于开发新的系统,需要将之前一个老的C/S应用的数据按照新的数据设计导入到新库中.此过程可能涉及到表结构不一致.大数据量(千万级,甚至上亿)等情况,包括异构数据的抽取.清洗等等工作.部分复杂的工作需要 ...
- RobotFramework安装扩展库包Selenium2Library(三)
Robot Framework扩展库包 http://robotframework.org/#libraries 一,自动化测试web端 1,pip安装SeleniumLibrary pip inst ...
- 使用脚本实现killproc的功能
在shell提示符号下输入type killproc,会发现killproc实在 /sbin/目录下,通过man killproc可以查看这个脚本(姑且这么称为脚本)的用法,现在,把这个脚本的实现过程 ...
- show engine innodb status 详细介绍
Contents Header1 SEMAPHORES. 1 LATEST DETECTED DEADLOCK. 3 TRANSACTIONS. 5 什么是purge操作... 5 FILE I/O. ...
- mvn简单命令
导出maven项目依赖的jar包 mvn dependency:copy-dependencies -DoutputDirectory=lib 编译Java代码 mvn compile eclipse ...
- tmux 使用
tmux命令参数 tmux new -s name //创建一个新会话 tmux ls //列出所有会话 tmux a -t name //返回某一个会话 tmux内部命令(ctrl+b之后按) s ...