(自用)learnOpenGL学习总结-光照-Light casters

文章讲述了在游戏或图形渲染中,修正了一个关于vertexShader中FragPos处理的错误,并介绍了平行光、点光源和聚光灯的概念,以及如何在fragmentshader中实现这些光照效果,包括边缘平滑处理和spotlight的衰减计算。
摘要由CSDN通过智能技术生成

一个错误的修正

在之前的basic lighting中,vertexShader中对于FragPos我写错了,不是简单的mat3(modelMat)* aPos,

而是

FragPos = (modelMat * vec4(aPos.xyz,1.0)).xyz;

这样,这是因为,对于坐标变换来说,一定要在四元坐标中来变换不然就会错!

所以,先变换再裁剪。


其实在前面的课程中已经出现了光,但是在那个时候我们只定义了lightColor 和 lightPos,不过,这既不是点光源又不是平行光,在这一节会具体写清楚光该如何实现已经封装成类。

平行光Directional Light)

写一个光的类,里面需要有什么元素呢。

对于平行光 需要有 方向和 颜色

class LightDirectional
{
public:
	LightDirectional(glm::vec3 _position, glm::vec3 _angles, glm::vec3 _color = glm::vec3(1.0f,1.0f,1.0f));

	glm::vec3 position;
	glm::vec3 angles;
	glm::vec3 direction = glm::vec3(0, 0, 1.0f);//pointing to Z
	glm::vec3 color;
	void UpdateDirection();

};

并且修改main中之前设置lightpos的地方,平行光只需要方向和颜色,

在前面声明一个角度是45°的光,前面的那个position就放在那里把,对结果没有影响。

#pragma region Light Declare
LightDirectional light(glm::vec3(10.0f, 10.0f, -5.0f), glm::vec3(glm::radians(45.0f), 0, 0));
#pragma endregion

.......
glUniform3f(glGetUniformLocation(testShader->ID, "lightColor"), light.color.r, light.color.g, light.color.b);
glUniform3f(glGetUniformLocation(testShader->ID, "lightDir"), light.direction.x, light.direction.y, light.direction.z);

点光源Point Light

那么点光源,他就不需要角度了,他需要什么参数呢,位置和颜色。

像上面一样重新建立一个新的点光源的类。

结果如下:

不过,这里面为了更加真实,需要加入衰减因子。

可以看到后面的物体变暗了,bingo!

聚光spotlight

聚光灯就是想舞台上的那种,虽然光从一个点出来,但是和点光源不同的是,他是有范围的。

和之前一样,思考一下一个spotlight需要什么参数,位置position,可以照亮的范围(或者说最大角度)(光切角)Cutoff Angle,和方向spotDir。

我们先抛开颜色,衰减不谈,对于这样的一个光源,最重要的是判断fragment是否可以被光打到。

这里有个很巧妙地思路,不考虑phy和theta谁大,而是直接看他们的cos大小。(因为单位向量点乘得到的标量就是cos)

所以,我们只需要计算cosPhy(这个我们可以直接给出)和cosTheta(这个用spotDIr和lightDIR点乘就行)比较。

ok,接下来就是代码实现。

	float cosTheta = dot( normalize(FragPos-lightPos), -1*lightDirUniform);
	if(cosTheta>lightS.cosPhy){
		//inside
		FragColor = vec4( ( ambient + (diffuse + specular))*objColor+emission, 1.0f);
	}
	else{
	//outside
		FragColor = vec4( ( ambient )*objColor+emission, 1.0f);
	}

最重要的是fragmentShader中,这里一定要保证两个向量的方向一致性。都让方向是从片段指向光源

不过还是有点假,边缘太硬了。而且没有遮挡(这部分在后面会学)先解决边缘问题。

平滑/软化边缘

这个图其实画反了,能理解就行。所以超出范围的角度,我还需要再扩大一点。

此外,我们可以把spot的影响抽象成spotratio,在范围内就是1,外就是0,中间就是过度。

	float SpotRatio;

	if(cosTheta>lightS.cosInnerPhy){
	//inside
		SpotRatio = 1.0f;
	}else if(cosTheta >lightS.cosOutPhy){
	//middle
		SpotRatio = (cosTheta-lightS.cosOutPhy)/(lightS.cosInnerPhy-lightS.cosOutPhy);
	}else{
	//outside
		SpotRatio = 0;
	}
	FragColor = vec4( ( ambient + (diffuse + specular)*SpotRatio)*objColor+emission, 1.0f);

这么些比较好看。

合理

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值