您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 3浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

LearnGL - 11.2 - 实现简单的Phong光照模型

Jave.Lin 发布时间:2020-07-21 11:05:20 ,浏览量:3

文章目录
  • Phong
  • Phong、Gouraud的区别
    • Gouraud的效果
      • diffuse
      • specular
    • Phong 效果
      • difusse
      • specular
          • 与 Gouraud-Phong 的高光效果图比较
      • 纯高光 Specular 的 Shader
  • GLSL Include 测试
  • 总结
LearnGL - 学习笔记目录

前一篇:LearnGL - 11.1 - 实现简单的Gouraud 光照模型 了解了 Gouraud 光照模型的基本认识。

这篇:我们将对 Phong 光照模型实现一个简单的实现。

提前吐槽一下,GLSL 中的 include 也是麻烦,因为 GLSL 没有文件系统,我查看了一篇还不错:OpenGL shader文件 include,后面有空我再加上,因为现在没有 include"my_file.xxx" ,所以很多重复性的代码,只能在每一个文件都有一份,实在蛋疼!

本人才疏学浅,如有什么错误,望不吝指出。

Phong

Phong Shading,也叫:冯氏着色,它是由谁在 Gouraud 基础上改进的模型,我暂时没去了解。

Phong、Blinn-Phong ,都是在 Gouraud 光照模型基础上稍作改进的模型。

有兴趣可以去搜索,这里不会详细讲解这些内容。

Phong、Gouraud的区别

在前一篇了解到 Gouraud-Phong 的实现,主要都是依赖 Vertex Shader(顶点着色器)阶段来计算的。

而 Phong 比较大的区别是,主要在 Fragment Shader(片元/片段着色器)阶段来计算的。

Phong 模型既然在 Fragment Shader 中计算的,那么就需要将相关的数据放到 Fragment Shader 中处理。如:Vertex Shader 阶段中的法线传入到插值数据到 Fragment Shader 中,那么每个片段的法线都过渡都会平滑多,那么光照效果差距就会很大。

看看效果:

Gouraud的效果

可以查看前一篇:LearnGL - 11.1 - 实现简单的Gouraud光照模型

diffuse

在这里插入图片描述

specular

在这里插入图片描述

Phong 效果 difusse

diffuse 漫反射的都差不多的效果,就不发了图了。

specular

主要是 specular 高光的效果相差比较大

在这里插入图片描述

与 Gouraud-Phong 的高光效果图比较

如下图,上面的的球体是使用 Phong,在法线经过了插值平滑,然后在 Fragment Shader 处理光照,效果比下面的球体使用 Gouraud-Phong 在 Vertex Shader 在计算光照的效果好很多。 在这里插入图片描述 弄个GIF来显示两个效果对比 在这里插入图片描述

纯高光 Specular 的 Shader
// jave.lin - testing_phong_only_specular_shading.vert
#version 450 compatibility

// transform matrix uniform
uniform mat4 mMat; 			// m.v.p 矩阵
uniform mat4 vMat; 
uniform mat4 pMat;
uniform mat4 IT_mMat;		// model matrix 的逆矩阵的转置矩阵

// vertex data
attribute vec3 vPos;		// 顶点坐标
attribute vec2 vUV0;		// 顶点纹理坐标
attribute vec3 vNormal;		// 顶点法线

// vertex data - interpolation
varying vec2 fUV0;			// 给 fragment shader 传入的插值
varying vec3 fNormal;		// 世界坐标顶点法线
varying vec3 fWorldPos;		// 世界坐标

// 将对象空间的法线转换到世界空间下的法线
vec3 ObjectToWorldNormal(vec3 n) {
	return normalize(mat3(IT_mMat) * n);	// 等价于:transpose(I_mMat) * vec4(n, 0)
}

void main() {
	vec4 worldPos = mMat * vec4(vPos, 1.0);	// 世界坐标
	fUV0 = vUV0;							// UV0
	fNormal = ObjectToWorldNormal(vNormal);	// 世界坐标顶点法线
	fWorldPos = worldPos.xyz;				// 世界坐标
	gl_Position = pMat * vMat * worldPos;	// Clip pos
}

// jave.lin - testing_phong_only_specular_shading.frag
#version 450 compatibility

// camera uniform
uniform vec3 _CamWorldPos;	// 镜头世界坐标

// object uniform
uniform float Glossy;		// 光滑度

// light uniform
uniform vec4 LightPos;		// 灯光世界坐标位置,w==0,或名是方向光,w==1说明是点光源,w == 0.5 是聚光灯

// interpolation - 插值数据
varying vec2 fUV0;					// uv 坐标
varying vec3 fNormal;				// 顶点法线
varying vec3 fWorldPos;		// 世界坐标

vec3 my_reflect(vec3 L, vec3 N) {
	return -L + 2 * N * dot(N, L);
}

void main() {
	vec3 worldNormal= normalize(fNormal);						// 世界坐标法线再次归一化一次,因为插值之后可能会导致不是归一化的值
	vec3 viewDir 	= normalize(_CamWorldPos - fWorldPos); 	    // 顶点坐标 指向 镜头坐标 的方向
	float S = 0;
	if (LightPos.w == 0) {
		// 下面使用的是Phong 光照模型
		// 如果是方向光,那么 LightPos.xyz 是灯光方向的反方向
		float LdotN = dot(LightPos.xyz, worldNormal);
		vec3 R = my_reflect(LightPos.xyz, worldNormal);
		float RdotV = max(0, dot(R, viewDir));
		if (LdotN > 0) {
			S = pow(RdotV, Glossy);
		}
	} else {
		// 点光源 或是 聚光灯
		if (LightPos.w == 1) {
			// 点光
		} else { // LightPos.w == 0.5,即:LightPos.w !=0 && LightPos.w != 1
			// 聚光灯
		}
	}
	gl_FragColor = vec4(S);
}
GLSL Include 测试

开头部分已经吐槽过 GLSL Include 很麻烦

因为 Include 内容有点多,我就独立成单篇文章来说明了,参考:LearnGL - 12 - GLSL include - GL_ARB_shading_language_include (Extensions扩展) - 各种踩坑

总结

虽然效果下 Phong 的好很多,但是,一般图形渲染一般光照计算考量于性能的话,一般我们会尽可能在 VS(Vertex Shader)在计算光照,因为一般顶点数并没有片段数量那么多。

关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.3553s