OpenGL学习脚印: 顶点数据传送和着色器处理2

OpenGL学习脚印: 顶点数据传送和着色器处理2

写在前面

本节内容翻译和整理自《Learning Modern 3D Graphics Programming》Chapter2内容。作为学习目的,本文提炼其主要观点,删除了大部分细节部分的详述内容。另外原文示例代码有它独有的框架组织方式,为了保持自己的一贯风格,这里重写了示例程序代码,如果发现错误,请纠正我。转载需经过作者同意。

通过本节,你可以了解到:

通过着色器修改图形颜色在顶点着色器中使用多个属性索引简单的颜色插值1.简单的线性颜色插值

正如《OpenGL学习脚印: 顶点数据传送和着色器处理1》所述,片元着色器中包含片元的屏幕坐标信息。这样我们可以通过这些坐标计算颜色值来指定三角形的颜色。

片元着色器可以这样书写:

#version 330out vec4 outputColor;void main(){float lerpValue = gl_FragCoord.y / 500.0f;outputColor = mix(vec4(1.0f, 1.0f, 1.0f, 1.0f),vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpValue);}这里,gl_FragCoord是一个内置变量,仅仅在片元着色器中可见。它是一个vec3类型变量,其中XY为屏幕坐标,它们的绝对值会随着屏幕分辨率而变化。记得,前面说过,屏幕左下角为(0,0),因此屏幕下方的点的Y值比上方的点小。这里假定500.0是屏幕宽度(除非你改变窗口大小),那么lerpValue的值将会在[0,1]之间。

上述代码的第二行,利用lerpValue进行颜色的线性插值,mix函数是GLSL提供了很多个标准函数中的一个。

补充:

线性插值计算颜色很简单,就是C(x)=color1*(1-x)+color2*x这里x在[0,1]之间,C(x)代表的则是x值处的颜色,这里使用lerpValue作为计算参数。

注意:用于mix的第三个参数必须在[0,1]之间,当然OpenGL不会进行严格检查,如果值不符合规定,函数值将是未定义的,未定义的意味着你将得不到你想要的颜色。

下面给出一个自己整理的示例,示例代码中三角形定义为等腰三角形,它的坐标和插值时计算与上述代码略有差别,但不影响解释结果。关于shader.h头文件,请参看《OpenGL学习脚印: 顶点数据传送和着色器处理1》,其他代码及运行效果如下:

文件一: vertex shader vertex.glsl

#version 330layout(location = 0) in vec4 pos;void main(){ gl_Position = pos;}

文件二: fragment shader fragment.glsl

#version 330out vec4 outputColor;void main(){float lerpValue = (gl_FragCoord.y-256.0f)/128.0f;outputColor = mix(vec4(1.0f,0.0f,0.0f,1.0f),vec4(0.0f,0.0f,1.0f,1.0f),lerpValue);}

文件三: shaderDemo.cpp

//依赖库glew32.lib freeglut.lib//使用着色器颜色插值绘制三角形#include <string>#include <vector>#include <GL/glew.h>#include <GL/freeglut.h>#include "shader.h"using namespace std;void userInit();void reshape(int w,int h);void display( void );void keyboardAction( unsigned char key, int x, int y );GLuint vboId;//vertex buffer object句柄GLuint vaoId;//vertext array object句柄GLuint programId;//shader program 句柄int main( int argc, char **argv ){glutInit(&argc, argv);glutInitDisplayMode( GLUT_RGBA|GLUT_DOUBLE);glutInitWindowPosition(100,100);glutInitWindowSize( 512, 512 );glutCreateWindow( "Triangle demo" );glewInit();userInit();glutReshapeFunc(reshape);glutDisplayFunc( display );glutKeyboardFunc( keyboardAction );glutMainLoop();return 0;}//自定义初始化函数void userInit(){ glClearColor( 0.0, 0.0, 0.0, 0.0 ); //顶点位置和颜色数据 const GLfloat vertices[] = {-0.5f,0.0f,0.0f,1.0f,0.5f,0.0f,0.0f,1.0f,0.0f,0.5f,0.0f,1.0f }; //创建vertex array object对象 glGenVertexArrays(1,&vaoId); glBindVertexArray(vaoId); //创建vertex buffer object对象 glGenBuffers(1,&vboId); glBindBuffer(GL_ARRAY_BUFFER,vboId); glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER,0); //从文件创建着色器std::vector<GLuint> idVector;idVector.push_back(Shader::createShader(GL_VERTEX_SHADER,"data\\vertex.glsl"));idVector.push_back(Shader::createShader(GL_FRAGMENT_SHADER,"data\\fragment.glsl"));programId = Shader::createProgram(idVector);}//调整窗口大小回调函数void reshape(int w,int h){glViewport(0,0,(GLsizei)w,(GLsizei)h);}//绘制回调函数void display( void ){glClear(GL_COLOR_BUFFER_BIT);glUseProgram(programId);glBindBuffer(GL_ARRAY_BUFFER,vboId);//启用顶点位置属性索引glEnableVertexAttribArray(0);glVertexAttribPointer(0,4,GL_FLOAT,GL_FALSE,0,0);//绘制三角形glDrawArrays(GL_TRIANGLES, 0, 3);glBindBuffer(GL_ARRAY_BUFFER,0);glUseProgram(0);glDisableVertexAttribArray(0);glutSwapBuffers();}//键盘按键回调函数void keyboardAction( unsigned char key, int x, int y ){switch( key ) {case 033: // Escape keyexit( EXIT_SUCCESS );break;}}运行效果如下图:

可以看到位于512屏幕中心x轴处颜色为红色,而顶部的顶点的颜色为蓝色,符合线性插值的预期效果。

2.使用多个属性索引来指定顶点位置和颜色所有的胜利,与征服自己的胜利比起来,都是微不足道

OpenGL学习脚印: 顶点数据传送和着色器处理2

相关文章:

你感兴趣的文章:

标签云: