着色器

文章推薦指數: 80 %
投票人數:10人

GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

着色器的开头总是要声明版本,接着是输入和输出变量、uniform和 main 函数。

每个着色器的入口 ... LearnOpenGL-CN 主页 简介 入门 OpenGL 创建窗口 你好,窗口 你好,三角形 着色器 着色器 GLSL 数据类型 输入与输出 Uniform 更多属性! 我们自己的着色器类 从文件读取 练习 纹理 变换 坐标系统 摄像机 复习 光照 颜色 光照基础 材质 光照贴图 投光物 多光源 复习 加载模型 Assimp 网格 模型 高级OpenGL 深度测试 模板测试 混合 面剔除 帧缓冲 立方体贴图 高级数据 高级GLSL 几何着色器 实例化 抗锯齿 高级光照 高级光照 Gamma校正 阴影 阴影映射 点阴影 CSM 法线贴图 视差贴图 HDR 泛光 延迟着色法 SSAO 实战 调试 文字渲染 2D游戏 Breakout 准备工作 渲染精灵 粒子   LearnOpenGL-CN Docs» 入门» 着色器 着色器 原文 Shaders 作者 JoeyDeVries 翻译 Django 校对 Geequlim 在HelloTriangle教程中提到,着色器(Shader)是运行在GPU上的小程序。

这些小程序为图形渲染管线的某个特定部分而运行。

从基本意义上来说,着色器只是一种把输入转化为输出的程序。

着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。

前面的教程里我们简要地触及了一点着色器的皮毛,并了解了如何恰当地使用它们。

现在我们会用一种更加广泛的形式详细解释着色器,特别是OpenGL着色器语言(GLSL)。

GLSL 着色器是使用一种叫GLSL的类C语言写成的。

GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。

每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。

如果你不知道什么是uniform也不用担心,我们后面会进行讲解。

一个典型的着色器有下面的结构: #versionversion_number intypein_variable_name; intypein_variable_name; outtypeout_variable_name; uniformtypeuniform_name; intmain() { //处理输入并进行一些图形操作 ... //输出处理过的结果到输出变量 out_variable_name=weird_stuff_we_processed; } 当我们特别谈论到顶点着色器的时候,每个输入变量也叫顶点属性(VertexAttribute)。

我们能声明的顶点属性是有上限的,它一般由硬件来决定。

OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性,你可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限: GLintnrAttributes; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS,&nrAttributes); std::cout< #include #include #include #include;//包含glew来获取所有的必须OpenGL头文件 classShader { public: //程序ID GLuintProgram; //构造器读取并构建着色器 Shader(constGLchar*vertexPath,constGLchar*fragmentPath); //使用程序 voidUse(); }; #endif Important 在上面,我们在头文件顶部使用了几个预处理指令(PreprocessorDirectives)。

这些预处理指令会告知你的编译器只在它没被包含过的情况下才包含和编译这个头文件,即使多个文件都包含了这个着色器头文件。

它是用来防止链接冲突的。

着色器类储存了着色器程序的ID。

它的构造器需要顶点和片段着色器源代码的文件路径,这样我们就可以把源码的文本文件储存在硬盘上了。

我们还添加了一个Use函数,它其实不那么重要,但是能够显示这个自造类如何让我们的生活变得轻松(虽然只有一点)。

从文件读取 我们使用C++文件流读取着色器内容,储存到几个string对象里: Shader(constGLchar*vertexPath,constGLchar*fragmentPath) { //1.从文件路径中获取顶点/片段着色器 std::stringvertexCode; std::stringfragmentCode; std::ifstreamvShaderFile; std::ifstreamfShaderFile; //保证ifstream对象可以抛出异常: vShaderFile.exceptions(std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::badbit); try { //打开文件 vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); std::stringstreamvShaderStream,fShaderStream; //读取文件的缓冲内容到流中 vShaderStream<Program=glCreateProgram(); glAttachShader(this->Program,vertex); glAttachShader(this->Program,fragment); glLinkProgram(this->Program); //打印连接错误(如果有的话) glGetProgramiv(this->Program,GL_LINK_STATUS,&success); if(!success) { glGetProgramInfoLog(this->Program,512,NULL,infoLog); std::cout<Program); } 现在我们就写完了一个完整的着色器类。

使用这个着色器类很简单;只要创建一个着色器对象,从那一点开始我们就可以开始使用了: ShaderourShader("path/to/shaders/shader.vs","path/to/shaders/shader.frag"); ... while(...) { ourShader.Use(); glUniform1f(glGetUniformLocation(ourShader.Program,"someUniform"),1.0f); DrawStuff(); } 我们把顶点和片段着色器储存为两个叫做shader.vs和shader.frag的文件。

你可以使用自己喜欢的名字命名着色器文件;我自己觉得用.vs和.frag作为扩展名很直观。

源码:使用新着色器类的程序,着色器类,顶点着色器,和片段着色器。

练习 修改顶点着色器让三角形上下颠倒:参考解答 使用uniform定义一个水平偏移量,在顶点着色器中使用这个偏移量把三角形移动到屏幕右侧:参考解答 使用out关键字把顶点位置输出到片段着色器,并将片段的颜色设置为与顶点位置相等(来看看连顶点位置值都在三角形中被插值的结果)。

做完这些后,尝试回答下面的问题:为什么在三角形的左下角是黑的?:参考解答 ReadtheDocs



請為這篇文章評分?