Qt OpenGL:学习现代3D图形编程之二,玩转色彩

网友投稿 694 2022-09-28 08:25:00

Qt OpenGL:学习现代3D图形编程之二,玩转色彩

除了给三角形赋予单一的颜色,我们还有两种方法来改变三角形表面的颜色,一种是利用片段的位置来计算颜色,另一种是利用每个顶点的数据来计算颜色。

一、利用片段位置计算颜色

片段的数据包括片段在屏幕上的位置,因此如果我们想要改变三角形表面的颜色,可以访问片段着色器中的数据,并计算片段最终的颜色。 gl_FragCoord是片段着色器独有的内置变量,它是个三维向量,包含x、y、z,其中x和y表示窗口坐标,z表示片段的深度值。需要注意的是,窗口坐标以窗口的左下角为原点,所以三角形底部片段的y值要小于顶部片段的y值。下面这个片段着色器使得片段的颜色基于它在窗口中的y值变化。500.0f是窗口的高度,main()函数中第一行的除法将y值转化到[0,1]范围,此时0表示窗口的底部,1表示窗口的顶部。第二行使用[0,1]之间的值来计算两种颜色之间的线性混合。mix函数是OpenGL着色器语言内置的标准函数,类似mix的很多函数都是向量化的,也就是说这些函数的参数可以是向量,当这些参数为向量时,向量的维数必须相同。mix的第三个参数必须是[0,1]之间的值,当它为0时,函数返回第一个参数,当它为1时,函数返回第二个参数,否则函数返回第一个参数和第二个参数的线性混合,该混合基于第三个参数。

const std::string strFragmentShader( "#version 330\n" "out vec4 outputColor;\n" "void main()\n" "{\n" " float lerpValue = gl_FragCoord.y / 500.0f;\n" " outputColor = mix(vec4(1.0f, 1.0f, 1.0f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpValue);\n" "}\n");

渲染后的效果是,当y靠近底部是,三角形接近白色;当y靠近顶部时,三角形接近黑色。如下图所示。

参考链接:const float vertexData[] = {      0.0f,    0.5f, 0.0f, 1.0f,      0.5f, -0.366f, 0.0f, 1.0f,     -0.5f, -0.366f, 0.0f, 1.0f,      1.0f,    0.0f, 0.0f, 1.0f,      0.0f,    1.0f, 0.0f, 1.0f,      0.0f,    0.0f, 1.0f, 1.0f, };

2.顶点着色器

这里我们定义了一个输出变量theColor,它用于将数据输出顶点着色器,这是通过关键字out来实现的。关键字smooth是插值限定符。顶点着色器只执行三次,产生三个位置输出(gl_Position)和三个颜色输出(theColor)。这三个位置构成一个三角形,该三角形接着被光栅化,产生大量(成千上万)片段。

const std::string strVertexShader( "#version 330\n" "layout(location = 0) in vec4 position;\n" "layout(location = 1) in vec4 color;\n" "smooth out vec4 theColor;\n" "void main()\n" "{\n" " gl_Position = position;\n" " theColor = color;\n" "}\n");

下图是顶点着色器的数据流图。

3.片段着色器

第二行定义了一个输入变量theColor,它与顶点着色器中的输出变量名字相同,这样片段着色器就可以从顶点着色器获取反馈信息。片段着色器执行次数与光栅化三角形时产生的片段数有关,有多少个片段,就执行多少次。theColor只从顶点着色器获取了三个颜色,那么这三个颜色是如果传递给各个片段的呢?答案是片段插值,每个片段获得的颜色是这三个颜色的混合,片段离三角形的哪个顶点越近,这个顶点的颜色在混合时所占的比重就越大。smooth定义了插值的方式,其他的两个插值限定符分别是noperspective和flat。使用smooth时,三角形表明的颜色会均匀变化;使用noperspective时,除非渲染过程复杂,否则看不出与smooth的区别;使用flat时,实际上关闭了插值,每个片段简单的使用顶点着色器输出的第一个颜色。需要注意的是,顶点着色器和片段着色器中相同变量的插值限定符必须相同。

const std::string strFragmentShader( "#version 330\n" "smooth in vec4 theColor;\n" "out vec4 outputColor;\n" "void main()\n" "{\n" " outputColor = theColor;\n" "}\n");

4.显示到屏幕

注意与《画一个三角形》中不同的地方。

void display(){ //指定OpenGL清理屏幕是将要使用的颜色,这里为黑色。 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //开始清理屏幕,GL_COLOR_BUFFER_BIT表示清理将影响颜色缓冲区,清理时使用上面指定的颜色。 glClear(GL_COLOR_BUFFER_BIT); //告知OpenGL渲染的时候需要调用应用程序对象。 glUseProgram(theProgram); //下面三行设置三角形的坐标,它们告知OpenGL三角形在缓冲区中的顶点位置和顶点颜色。 //获取已经初始化的缓冲区对象。 glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); //启用缓冲区对象中的数据,参数指定要修改的顶点属性的索引值。在缓冲区对象中有位置和颜色两个数组,我们 //必须告诉OpenGL如何取到这两组数据。这两组数据对应两个顶点属性,在顶点着色器中属性位置是layout(location=0) //和layout(location=1),因此,属性的索引值需要用glEnableVertexAttribArray函数指定两次。 glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); //尽管这个函数包含“Pointer”,但是它不处理指针,它用来对缓冲区对象中的顶点属性进行设定。 //参数1指定要修改的顶点属性的索引值;参数2指定每个顶点向量的维数;参数3指定每个顶点向量的数据类型; //参数4指定是否归一化;参数5指定各顶点向量间是否有空隙,0表示紧密排列;参数6指定顶点数组起始位置与缓冲区 //对象起始位置的偏移量,0表示无偏移。后三个参数通常取默认值。 //48=4*4*3,48之前加(void*),是因为这个参数就是一个void指针。 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)48); //渲染函数,从顶点数组索引0开始,读取3个顶点,然后将他们连接成一个三角形。 glDrawArrays(GL_TRIANGLES, 0, 3); //下面两行是清理工作,释放为了实现渲染所做的一些设置。 glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glUseProgram(0);}

渲染后的效果如下图所示。

参考链接:http://alfonse.bitbucket.org/oldtut/Basics/Tutorial%2002.html

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Qt播放PCM音频(裸流)文件的两种方法
下一篇:「首席架构师推荐」精选企业门户系统列表
相关文章