LearnGL - 11.4 - 实现简单的Flat BlinnPhong光照模型

文章目录

  • GLSL flat
  • Flat 风格
  • Shader
  • References

LearnGL - 学习笔记目录

前些篇:

  • LearnGL - 11.1 - 实现简单的Gouraud-Phong光照模型
  • LearnGL - 11.2 - 实现简单的Phong光照模型
  • LearnGL - 11.3 - 实现简单的Blinn-Phong光照模型

了解了 Gouraud-Phong、Phong、Blinn-Phong 光照模型的基本认识。

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

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


GLSL flat

GLSL 中如何对顶点传到片段着色器的数据指定不插值,可以参考:GLSL 中实现类似 Unity noiterpolation

实现起来非常简单,值要对法线数据不插值即可,这也可以在 Gouraud-Phong 来实现更节省性能。

LearnGL - 11.4 - 实现简单的Flat BlinnPhong光照模型_第1张图片

GIF

Flat 风格

一般有些游戏风格是简模、平旦着色(Flat Shading) 都可以使用

如下:
LearnGL - 11.4 - 实现简单的Flat BlinnPhong光照模型_第2张图片

Shader

Flat Blinn-Phong 的就不发出来了,只是在VS,FS中对法线插值数据添加上 flat 关键字即可。

所以这里只发一个性能上稍微好一些的 Flat Gouraud-Phong in vs 的 shader

// jave.lin - testing_flat_shading_in_vs.vert - 测试 phong 光照模型
#version 450 compatibility

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

// object uniform
uniform float Glossy;		// 光滑度
uniform vec3 DiffuseK;		// 漫反射系数
uniform vec3 SpecularK;		// 高光系数

// light uniform
uniform vec4 LightPos;		// 灯光世界坐标位置,w==0,或名是方向光,w==1说明是点光源,w == 0.5 是聚光灯
uniform vec4 LightColor;	// 灯光颜色,.xyz 顔色,.w 强度
// uniform vec3 LightDir;		// 灯光类型为聚光灯的方向

// 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 传入的插值
flat varying vec3 fDiffuse; 		// 漫反射颜色
flat varying vec3 fSpecular; 	// 高光颜色
// varying vec3 fNormalTest;

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

vec3 my_reflect(vec3 L, vec3 N) {
	// return -L + 2 * N * dot(N, L);
	return -L + 2 * dot(N, L) * N; // 优化调整分量相同先乘
}

void main() {
	vec4 worldPos = mMat * vec4(vPos, 1.0);	// 世界坐标
	vec3 viewDir = normalize(_CamWorldPos - worldPos.xyz); 	// 顶点坐标 指向 镜头坐标 的方向
	vec3 worldNormal = ObjectToWorldNormal(vNormal);		// 获取世界坐标下的法线
	// fNormalTest = worldNormal;
	// phong shading

	if (LightPos.w == 0) {
		// 下面使用的是Phong 光照模型
		// 如果是方向光,那么 LightPos.xyz 是灯光方向的反方向
		float LdotN = max(0, dot(LightPos.xyz, worldNormal));
		fDiffuse = LightColor.rgb * LightColor.w * DiffuseK * LdotN; // lambert
		// fNormalTest = vec3(LdotN);
		vec3 R = my_reflect(LightPos.xyz, worldNormal);
		float RdotV = max(0, dot(R, viewDir));
		if (LdotN > 0) {
			fSpecular =  LightColor.rgb * LightColor.w * SpecularK * pow(RdotV, Glossy);
		} else {
			fSpecular = vec3(0, 0, 0);
		}
	} else {
		// 点光源 或是 聚光灯
		if (LightPos.w == 1) {
			// 点光
		} else { // LightPos.w == 0.5,即:LightPos.w !=0 && LightPos.w != 1
			// 聚光灯
		}
	}
	// uv0
	fUV0 = vUV0;
	// fNormalTest = worldNormal;
	gl_Position = pMat * vMat * worldPos;
}

// jave.lin - testing_flat_shading_in_vs.frag - 测试 phong 光照模型
#version 450 compatibility

uniform vec4 _Ambient;		// .xyz 环境光颜色, .w 环境光系数
uniform int AmbientType;		// 环境光类别,测试用

// interpolation - 插值数据
varying vec2 fUV0;					// uv 坐标
flat varying vec3 fDiffuse; 				// 漫反射颜色
flat varying vec3 fSpecular; 			// 高光颜色
// varying vec3 fNormalTest;

// local uniform
uniform sampler2D main_tex;			// 主纹理

void main() {
	// gl_FragColor 	= vec4(fNormalTest, 1.0);
	// return;
	vec3 albedo 	= texture(main_tex, fUV0).rgb;

	vec3 ambient;
	if (AmbientType == 0) {
		ambient = _Ambient.rgb * _Ambient.a;
	} else {
		ambient = mix(_Ambient.rgb * _Ambient.a, albedo, _Ambient.a);
	}

	gl_FragColor 	= vec4(ambient +  albedo * fDiffuse + fSpecular, 1.0);
}

References

  • GLSL 中实现类似 Unity noiterpolation

你可能感兴趣的:(OpenGL)