learnOpenGL 2.4 投光物

多个箱子

创建多个箱子的过程与第一章中类似,下面是主程序中的代码

	glm::vec3 cubePositions[] = {
	...};

	glBindVertexArray(cubeVAO);
        for (int i = 0; i < 10; i++)
        {
            glm::mat4 model = glm::mat4(1.0f);
            model = glm::translate(model, cubePositions[i]);
            float angle = 20.0f * i;
            model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
            lightingshader.setMat4("model", model);
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }

值得注意的是,要记得改变顶点着色器中箱子的法向量,否则它的光照将会很诡异

void main()
{
...
    Normal = mat3(transpose(inverse(model))) * aNormal; 
 ...
}

平行光

在这里插入图片描述
太阳光是最常见的一种平行光,平行光通常不需要设定光源的位置,只需要知道其方向,因此我们在light结构体中添加一个方向向量。

struct Light {
    // vec3 position; // 使用定向光就不再需要了
    vec3 direction;

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};
...
void main()
{
  vec3 lightDir = normalize(-light.direction);
  ...
}

**注意我们首先对light.direction向量取反。**我们目前使用的光照计算需求一个从片段至光源的光线方向,但人们更习惯定义定向光为一个从光源出发的全局方向。


衰减

现实中,光照强度随距离衰减,公式如下
在这里插入图片描述

公式中的Kc固定为1,另外两个参数根据我们需要光覆盖的距离而变化,下面是部分对照表
在这里插入图片描述
为了实现衰减,我们在结构体中加入这3个参数,并依照公式进行计算

struct Light {
    vec3 position;  

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;

    float constant;
    float linear;
    float quadratic;
};

float distance    = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));

ambient  *= attenuation; 
diffuse  *= attenuation;
specular *= attenuation;

聚光

在这里插入图片描述
现实中光源通常不会照亮所有方向,而是照亮一个圆锥形的区域,如上图所示

对于这种光源,既要设定光源的位置light.position,也要设定它的方向light.direction。

注意,light.direction 是光源正对的方向,即上图中的红线。它是从光源指向片段的。
lightDir 是片段到光源的方向,即上图中的黑箱,它是从片段指向光源的。

上图中的蓝线是光照的边缘,称为切光(cutoff)。而现实中,光照范围的边缘往往是羽化模糊的。所以我们又设置了一个完全变暗的边界outercutoff。

如图,light.direction与lightDir夹角的cos值记为θ,注意这两个向量方向不同,计算时要将light.direction取反

内切光与中心夹角的cos记为light.cutoff,外切光记为light.outercutoff

利用以下公式就可实现内外切光的过渡
在这里插入图片描述
取点在内切之内时,I>1,在内外切之间,1>I>0,在外切以外,I<0。
我们可以利用clamp函数,让I>1时取1,I<0时取0.

float theta     = dot(lightDir, normalize(-light.direction));
float epsilon   = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);    
...
// 将不对环境光做出影响,让它总是能有一点光
diffuse  *= intensity;
specular *= intensity;
...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值