您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 3浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

LearnGL - 13 - PointLight - 点光源

Jave.Lin 发布时间:2020-07-28 17:28:01 ,浏览量:3

文章目录
  • 点光源
    • 与方向光比较
    • 光衰减
      • 距离衰减
      • 作用范围衰减
    • 对应的 Inspector 面板参数
  • 演示
  • 光源的切换
  • Shader
  • References
LearnGL - 学习笔记目录

前些篇:

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

这些演示光照计算中,都是对 “方向光” 类型的光源来实现的

这篇:我们尝试给 “点光源” 类型的光源

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

先看一下我们的效果静态图: 在这里插入图片描述

点光源 与方向光比较
  • 方向光 : 只 考虑方向,不考虑位置,而且他的光强度假设是不衰减的
  • 点光源 : 刚好相反,不考虑方向,但需要 考虑光源位置,而且它的光强度会随距离而衰减
光衰减 距离衰减

目前参考了网上提供的衰减曲线,因为直线型的衰减效果不太好 在这里插入图片描述 Y轴数值我放大了100倍,因为实际 shader 中使用是 0~1 的一致衰减值

衰减公式为: a t t e n d ( d ) = 1 K c + K l ⋅ d + K q ⋅ d 2 atten_d(d)=\frac{1}{K_c+K_l \cdot d + K_q \cdot d^2} attend​(d)=Kc​+Kl​⋅d+Kq​⋅d21​

  • d d d 是距离
  • K c K_c Kc​ 是常数项系数,通常为1,为了避免除以零
  • K l K_l Kl​ 是一次项系数
  • K q K_q Kq​ 是二次项系数
作用范围衰减

但是因为我的点光源为了优化,添加了一个 range 参数,即:点光源的影响范围,所以我给上面的衰减模型公式添加了另一个衰减值:atten_r, r r r 是光源指定的有效的范围值 a t t e n r ( r ) = 1 − 1 r , ( 0 ≤ r ≤ 指 定 的 范 围 值 ) atten_r(r)=1-\frac{1}{r}, (0 \le r \le 指定的范围值) attenr​(r)=1−r1​,(0≤r≤指定的范围值)

所以我的 a t t e n ( x ) atten(x) atten(x) 调整为: a t t e n ( d , r ) = a t t e n d ( d ) ⋅ a t t e n r ( r ) atten(d,r)=atten_d(d) \cdot atten_r(r) atten(d,r)=attend​(d)⋅attenr​(r)

用 GGB 可以调整系数查看效果: 在这里插入图片描述 在这里插入图片描述

对应的 Inspector 面板参数

在这里插入图片描述 首先是需要选择为 Point 点光源

  • Atten Kc 对应的常数项系数
  • Atten Kl 一次项系数
  • Atten Kq 二次项系数
  • Range 就是我们指定该点光源能作用的范围大小
演示

为了方便查看点光源的效果,先将镜头的 clearColor 设置为纯黑色 在这里插入图片描述

再关闭环境光: AmbientIntensity = 0 在这里插入图片描述 调整 Range 参数查看效果,并调整一下灯光颜色 在这里插入图片描述

光源的切换

我给编辑器中的光源作了类似 Gizmos 的显示切换

  • 方向光 目前显示的是一个 Cube,从黑色指定有颜色的方向就是光源入射方向
  • 点光源 目前实现的是一个 Sphere,不用考虑方向,但需要考虑位置

在这里插入图片描述

Shader

主要是查看:my_lighting.glsl 的引用文件(GLSL 中如何实现 include 可以查看我之前的一篇:LearnGL - 12 - GLSL include - GL_ARB_shading_language_include (Extensions扩展) - 各种踩坑)

// jave.lin - my_lighting.glsl - 光照模型处理

#include "/Include/my_global.glsl"

#ifndef _MY_LIGHTING__GLSL__
#define _MY_LIGHTING__GLSL__

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

// 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;		// 灯光类型为聚光灯的方向

// point light
uniform float PL_Kc;		// 点光源 常数项系数
uniform float PL_Kl;		// 点光源 一次项系数
uniform float PL_Kq;		// 点光源 二次项系数
uniform vec2 PL_Range;		// 点光源 有效范围, .x == range, .y == 1.0 / range

// TODO : 实现多光源时使用,现在单光源先不写
// struct LightData_t {
// };

// const uint MaxLightNum = 10;
// uniform LightData_t Lights[MaxLightNum];

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

// point light
float getDistanceAtten(float dist) {		// 获取距离衰减
	return 1.0 / (PL_Kc + PL_Kl * dist + PL_Kq * (dist * dist));
}
float getRangeAtten(float dist) {			// 获取范围衰减
	return clamp(dist * PL_Range.y == 0 ? 0 : 1 - dist * PL_Range.y, 0, 1);
}

void phong_illumination(
    in vec3 worldNormal,
    in vec3 viewDir,
    in vec3 worldPos,
    out vec3 diffuse,
    out vec3 specular
    ) {

	vec3 lightDir;
	float atten = 1;
    if (LightPos.w == 0) {
		// 下面使用的是Phong 光照模型
		// 如果是方向光,那么 LightPos.xyz 是灯光方向的反方向
		lightDir = LightPos.xyz;
		
	} else {
		// 点光源 或是 聚光灯
		if (LightPos.w == 1) {
			// 点光
			lightDir = LightPos.xyz - worldPos;
			float dist = length(lightDir);
			lightDir *= dist == 0 ? 1 : 1.0 / dist;
			// lightDir = normalize(lightDir);
			atten = getDistanceAtten(dist) * getRangeAtten(dist);
		} else { // LightPos.w == 0.5,即:LightPos.w !=0 && LightPos.w != 1
			// 聚光灯
		}
	}
	float D = max(0, dot(lightDir, worldNormal));
	diffuse = LightColor.rgb * LightColor.a * D * DiffuseK * atten;
	vec3 H = normalize(lightDir + viewDir);
	float S = 0;
	if (D > 0) S = pow(max(0, dot(H, worldNormal)), Glossy);
	specular = LightColor.rgb * LightColor.a * S * SpecularK * atten;
}

#endif

my_global.glsl

// jave.lin - my_global.glsl

#ifndef _MY_GLOBAL__GLSL__
#define _MY_GLOBAL__GLSL__

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

// local uniform
uniform mat4 mMat; 			// m 矩阵
uniform mat4 vMat; 			// v 矩阵
uniform mat4 pMat; 			// p 矩阵
uniform mat4 mvpMat; 		// m.v.p 矩阵
uniform mat4 IT_mMat;		// Model Matrix 的逆矩阵的转置矩阵

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

vec3 getWorldViewDir(vec3 worldPos) {
	return normalize(_CamWorldPos - worldPos);
}

#endif /* _MY_GLOBAL__GLSL__ */ // 这里一定要加 /* 你的头文件宏 */,否则会报错,太无语了

接着是使用渲染对象的 shader

// jave.lin - testing_includes.vert
#version 450 compatibility
#extension GL_ARB_shading_language_include : require
#include "/Include/my_global.glsl"

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

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

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_includes.frag
#version 450 compatibility
#extension GL_ARB_shading_language_include : require
#include "/Include/my_global.glsl"
#include "/Include/my_lighting.glsl"

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

uniform sampler2D main_tex;

void main() {

	vec3 albedo 	= texture(main_tex, fUV0).rgb;

	vec3 worldNormal= normalize(fNormal);						// 世界坐标法线再次归一化一次,因为插值之后可能会导致不是归一化的值
	vec3 viewDir 	= getWorldViewDir(fWorldPos); 	    		// 顶点坐标 指向 镜头坐标 的方向

	vec3 diffuse 	= vec3(0);
	vec3 specular	= vec3(0);

    vec3 ambient 	= getAmbient(albedo);

	phong_illumination(worldNormal, viewDir, fWorldPos, diffuse, specular);

	gl_FragColor = vec4(ambient + diffuse * albedo + specular, 1.0);
}
References
  • 投光物
关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.3283s