OpenGL学习(4)

给图形上色

对于图形的上色有两种基本的方法: 直接使用glColor~() 系列的函数 使用shader脚本。下文将简要介绍下这两种方法。

1.直接使用glColor~() 系列的函数

方法:在相应的坐标顶点使用该函数,如下程序所示

<span style="white-space:pre">	</span>glBegin(GL_TRIANGLES);
		glColor3f(1.0f,0.0f,0.0f);//set the red
		glVertex3f(-1.0f,-1.0f,0.0f);
		glColor3f(0.0f,1.0f,0.0f);//set the green
		glVertex3f(1.0f,-1.0f,0.0f);
		glColor3f(0.0f,0.0f,1.0f);//set the blue
		glVertex3f(0.0f,1.0f,0.0f);
	glEnd();

需要说明的是,每一个glColor~() 函数都是从开始使用处生效,在出现另一个glColor~() 函数时失效

调试运行结果:如图1所示


图1
小结:
这种方法在程序理解和写法上比较简单,但传输效率比较低;在多顶点的情况下,程序比较冗长;

2.使用shader脚本

方法:通过将颜色写在frangment(片元)脚本上,来实现图形着色
首先,编写读取shader脚本的程序。该程序包括如下:
(1)利用glCreateShader() 函数创建 vertex shader (顶点着色器)和 fragment shader(片元着色器)
	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);

	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

(2)利用getline() 函数读取 vertex shader 和 fragment shader

<span style="white-space:pre">	</span>std::string VertexShaderCode;
	std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
	if(VertexShaderStream.is_open())
	{
		std::string Line = "";
		while(getline(VertexShaderStream, Line))
			VertexShaderCode += "\n" + Line;
		VertexShaderStream.close();
	}
	else//Open vertex shader source code failed
	{
		printf("Failed to open %s. Are you in the right directory ? \n", vertex_file_path);
		return ;
	}

	std::string FragmentShaderCode;
	std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
	if(FragmentShaderStream.is_open())
	{
		std::string Line = "";
		while(getline(FragmentShaderStream, Line))
			FragmentShaderCode += "\n" + Line;
		FragmentShaderStream.close();
	}
	else
	{
		printf("Failed to open %s. Are you in the right directory ? \n", fragment_file_path);
		return ;
	}

(3-1)使用glCompileShader() 函数编译vertex shader,并根据其日志判断是否存在代码语法错误

<span style="white-space:pre">	</span>GLint Result = GL_FALSE;
	int InfoLogLength;

	printf("Compiling shader : %s\n", vertex_file_path);
	char const * VertexSourcePointer = VertexShaderCode.c_str();
	glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
	glCompileShader(VertexShaderID);

	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
 	if ( InfoLogLength > 0 )
	{
		std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
		glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
		printf("%s\n", &VertexShaderErrorMessage[0]);
	}

(3-2)同样,使用glCompileShader() 函数编译fragment shader,并根据其日志判断是否存在代码语法错误

<span style="white-space:pre">	</span>printf("Compiling shader : %s\n", fragment_file_path);
	char const * FragmentSourcePointer = FragmentShaderCode.c_str();
	glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
	glCompileShader(FragmentShaderID);

	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if ( InfoLogLength > 0 )
	{
		std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
		glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
		printf("%s\n", &FragmentShaderErrorMessage[0]);
	}

(4)使用glLinkProgram() 函数,将shader 和程序Link起来

<span style="white-space:pre">	</span>printf("Linking program\n");
	m_uiProgramID = glCreateProgram();
	glAttachShader(m_uiProgramID, VertexShaderID);
	glAttachShader(m_uiProgramID, FragmentShaderID);
	glLinkProgram(m_uiProgramID);

(5)再次检查脚本,并释放相关shader

<span style="white-space:pre">	</span>glGetProgramiv(m_uiProgramID, GL_LINK_STATUS, &Result);
	glGetProgramiv(m_uiProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if ( InfoLogLength > 0 )
	{
		std::vector<char> ProgramErrorMessage(InfoLogLength+1);
		glGetProgramInfoLog(m_uiProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
		printf("%s\n", &ProgramErrorMessage[0]);
	}

	glDetachShader(m_uiProgramID, VertexShaderID);
	glDetachShader(m_uiProgramID, FragmentShaderID);

	//Delete the vertex and fragment shader
	glDeleteShader(VertexShaderID);
	glDeleteShader(FragmentShaderID);

其次,编写vertex shader 和 fragment shader。
(1)关于vertex shader:基本包括,OpenGL版本声、定义存储顶点变量、传输顶点数据

#version 330 core

layout(location = 0) in vec3 vertexPosition_modelspace;

void main(){

	gl_Position =  vec4(vertexPosition_modelspace,1);

}

(2)关于fragment shader:基本包括,OpenGL版本声明、定义存储颜色变量、设定颜色数据

#version 330 core

out vec3 color;

void main()
{
	color = vec3(1,0,0);

}

最后,通过glUseProgram() 函数来激活所载入的shader。剩余步骤如前使用VBO画三角形的方法一样,即“使能顶点属性数组->绑定缓冲区->设置顶点属性值->画图形->禁止顶点属性数组”

glUseProgram(m_uiProgramID);

运行调试结果:如图2所示

图2
小结:
使用shader来进行着色,充分地利用GPU进行上色,极大地提高了编码的灵活性;但是在程序的理解上比较难,写法上也比较繁琐;需要说的是,对于读取shader的程序只要在一组shader(包括vertex shader 和 fragment shader)中,只要调用一次。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值