LearnOpenGL学习笔记(二)——着色器简单理解

       着色器在OpenGL中发挥着重要作用,它就像一个画笔,将输入的数据流,转为数学坐标,再将三维坐标变成二维坐标(针对我们现在用的二维显示器,全息显示器肯是三维的),再把二维坐标实际的像素点位置(这里面肯定存在的粗略的误差,比如(3.423,234.232)肯定在实际像素中不存在,要转换成邻近的),然后再往里面填充色彩,透明度之类的参数。      准确来说其实就是两步工作1.确定位置2.填充色彩。       处于输入输出与处理接口分开的原则,我们不考虑输入的数据具体是什么,这里只讨论如何去处理数据。

这里先上一张图,着色器程序分为六个小着色器部分,每个负责一部分

 


这里先解释一个专业术语“图形渲染管线”,这个就是上图显示的,像生产线一样的一条“管道”,进去数据流,出来一个像素画面。 当然咱们只可以编写三个着色器阶段,其中顶点着色器和片段着色器没有默认的,所以我们一开始只需要编写这两个简单的就可以了。 注意着色器严格来讲不是用c语言去编写的,而是一种GLSL的类c语言,它是c语言的变种,我们常把写好的着色器程序作为一个字符串,再运行的时候用一个函数(c语言编译器肯定没法编译glsl,需要一个函数进行转换)动态编译,然后将机器码放在GPU显存上运行。

接下来我们讨论如何去写着色器:

一个典型的着色器有下面的结构:
#version version_number//版本声明。一般版本必须和opengl一致,此外还有模式声明
in type in_variable_name;//输入变量类型声明
in type in_variable_name;

out type out_variable_name;//输出变量类型声明

uniform type uniform_name;

int main(){
  // 处理输入并进行一些图形操作
  ...
  // 输出处理过的结果到输出变量
  out_variable_name = weird_stuff_we_processed;
}
看得出着色器语言的程序,关键在于1.得到上一阶段的数据2,将数据处理3,把数据交给下一阶段
对于实现第一步和第三步,GLSL语言都有方便手段,就是IN,OUT关键字。只要在main函数前面声明的out 都将自动传递给接下来的着色器
同样着色器必须接受相同的in  同名变量数据输入。
也就是说,如果在顶点着色器声明了一个out  vec3 aaa变量,那么接下来在片段着色器声明一个in vec aaa变量,那么自动这两个变量都会链接在一
起,数据自动传递过来。
//注意在着色器程序中,六个着色器都是独立的,in out是它们的通讯手段,它们本身是六个独立的小程序,变量都是独立的,传递是一种赋值
手段。

Uniform: 在程序中,我们想要实现动画,也就是说每次渲染都有变化,这种变化是连续的,那么我们就需要程序CPU和着色器(渲染),相互配合,在每次渲染中都改变,也就是我们需要一种可以在着色器程序和CPU程序相互交流的工具。所以我们需要一种独立于六个小程序,处于着色器程序的全局变量用来交流,否则我们无法告知CPU的程序如何去联系位于哪个小着色器上的变量(别忘了,我们在构建好着色器程序后,就删除了六个小程序编译的码)。

      uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。第二,无论你
把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。我们可以在任何着色器中定义它们,而无需通过顶点着
色器作为中介。
#version 330 core 
out vec4 FragColor; 
uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量 
void main() { 
FragColor = ourColor; 
}

接下来我们跳出来,在CPU上改变我们的数据,然后再传入着色器里好了。
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
这个函数得到了着色器这个变量的索引,我们用它就可以修改着色器上的uniform了。
glUseProgram(shaderProgram); //先启动这个着色器
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
//glUniform函数就是用来修改的,4f是因为c语言不存在重载,所以我们只能命名n个类似函数名函数了

我们加入一些随时间改变的量,在每次渲染时都改变一点颜色(一秒钟五十次),就可以看到这样动画了。
float timeValue = glfwGetTime(); 
float greenValue = sin(timeValue) / 2.0f + 0.5f; 
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); 
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); 

uniform对于设置一个在渲染迭代中会改变的属性是一个非常有用的工具,它也是一个在程序和着色器间数据交互的很好工具            

posted @ 2019-04-15 18:54  落剑仙zobol  阅读(1020)  评论(0编辑  收藏  举报