opengl 设置每个点的颜色_OpenGL基本光照模型的GLSL实现

本文是OpenGL 4.0 Shading Language Cookbook的学习笔记,探讨了如何使用多个点光源、方向光源进行着色,以及逐像素着色、半角向量优化、模拟聚光灯、卡通风格和雾的效果。详细介绍了每个主题的实现步骤和GLSL代码示例,旨在提高渲染的真实感和性能。
摘要由CSDN通过智能技术生成

本文是OpenGL 4.0 Shading Language Cookbook的学习笔记

在本文我们将介绍下面这些内容:

  • 使用多个点光源进行着色
  • 使用方向光源进行着色
  • 使用逐像素着色来提高真实感
  • 使用半角向量提高性能
  • 模拟聚光灯
  • 模拟卡通风格
  • 模拟雾的效果

使用多个点光源进行着色

使用多个光源进行着色时,我们需要对每个光源进行计算,然后把它们的结果相加,最后得到表面反射的光的强度。很自然的,我们可以通过uniform数组来存储光源的位置和光的强度。在这里我们使用一个uniform结构体数组来存储所有光源信息。

d2972027acfba10eb283ace4d3384ceb.png

设置OpenGL程序的顶点位置属性的location为0,法线location为1。

创建使用 ADS(Phong)光照模型的多光源着色器程序的步骤如下:

1. 使用下面的顶点着色器:

#version 400
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
out vec3 Color;
struct LightInfo {
    
	vec4 Position; // Light position in eye coords.
	vec3 Intensity; // Light intensity
};
uniform LightInfo lights[5];
// Material parameters
uniform vec3 Kd; // Diffuse reflectivity
uniform vec3 Ka; // Ambient reflectivity
uniform vec3 Ks; // Specular reflectivity
uniform float Shininess; // Specular shininess factor
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 MVP;
vec3 ads( int lightIndex, vec4 position, vec3 norm )
{
    
	vec3 s = normalize( vec3(
			lights[lightIndex].Position –
			position) );
	vec3 v = normalize(vec3(-position));
	vec3 r = reflect( -s, norm );
	vec3 I = lights[lightIndex].Intensity;
	return
		I * ( Ka +
		Kd * max( dot(s, norm), 0.0 ) +
		Ks * pow( max( dot(r,v), 0.0 ),
		Shininess ) );
}
void main()
{
    
	vec3 eyeNorm = normalize( NormalMatrix *
			VertexNormal);
	vec4 eyePosition = ModelViewMatrix *
	vec4(VertexPosition,1.0);
	//Evaluate the lighting equation for each light
	Color = vec3(0.0);
	for( int i = 0; i < 5; i++ )
		Color +=ads( i, eyePosition, eyeNorm);
	gl_Position = MVP * vec4(VertexPosition,1.0);
}

2. 使用下面的片段着色器:

#version 400
in vec3 Color;
layout( location = 0 ) out vec4 FragColor;
void main() {
    
	FragColor = vec4(Color, 1.0);
}

3. 在OpenGL程序中设置光源数组,代码类似下面:

prog.setUniform("lights[0].Intensity", vec3(0.0f,0.8f,0.8f) );
prog.setUniform("lights[0].Position", position );

光源信息存储在lights数组中,示例使用了5个光源。光强存储在Intensiy域中,观察坐标系下的位置信息存储在Position域中。

函数ads负责光照计算。lightIndex表示光源信息数组索引。

main函数里的for循环计算每一个光源,并将结果相加写入Color变量。

片段着色器直接输出了插值后Color变量。

使用方向光源进行着色

着色公式的核心组成部分是从表面到光源的向量(也就是前面示例中的s)。对于距离非常远的光源,整个物体表面到光源的向量变化并不大。也就是说,对于非常遥远的光源,表面上的点到光源的向量是相同的。(也可以认为此时光源发出的光线是平行的。)这一光照模型可以用来模拟远距离光源,比如太阳。通常这样的光源被叫做方向光源,它没有位置信息,只有方向。我们实际上忽略掉了光强随距离平方衰减,然而,对于方向光源,这是常见做法。

对于方向光源,场景中的所有点到光源的方向都是相同的,所以,就不需要重复计算表面上的点到光源的方向,从而提高着色性能。

当然,点光源和方向光源的光照效果会有视觉上的差异。下面左图使用点光源渲染,右图使用方向光源渲染。左图的点光源在距离圆环较近的某个地方,由于平行光的原因右图相比左图有更多位置被照亮。

423c6fdf45b8e3f209cefa47ca78d64b.png

OpenGL的传统管线,使用光源位置的第四个成分来确定它是否为方向光源。如果第四个成分为0,则它为方向光源,位置信息是光源的方向向量。如果为1,位置信息被作为光源位置。在本例,我们使用同样的处理。

设置OpenGL程序的顶点位置的location为0,法线location为1。

使用下面的代码创建方向光源的ADS着色程序:

1. 使用下面的顶点着色器:

#version 400
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
out vec3 Color;
uniform vec4 LightPosition;
uniform vec3 LightIntensity;
uniform vec3 Kd; // Diffuse reflectivity
uniform vec3 Ka; // Ambient reflectivity
uniform vec3 Ks; // Specular reflectivity
uniform float Shininess; // Specular shininess factor
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;
vec3 ads( vec4 position, vec3 norm )
{
    
	vec3 s;
	if( LightPosition.w == 0.0 )
		s = normalize(vec3(LightPosition));
	else
		s = n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值