23.1 环境光 我躲在房间里,客厅的灯开着。 光从房间门缝里透进来,房间里也有了微弱的光,勉强能看清楚东西。 这是因为光子从门缝进到房间后,会不断反射到房间其他角落。 不过从门缝进到房间的光子比较少,大部分光子在不断反弹耗尽能量后,没有进入到人的眼睛。 仅少部分光子进入眼睛,所以看起来很暗。 晚上到农村去,虽然很暗,但是也不会,伸手看不见五指。 这是因为有少量的光子,从月亮反射到地球,再反射到我们的眼睛。 游戏里实际上也并不会出现纯黑的场景,不然玩家怎么操作。 我们将这种间接的、很微弱的光,称之为环境光。 先来看下这一节实现的效果吧。 光的通用属性 自然界的光是由多种波长的光子组成的,可见光也有很多种,不能被物体吸收的光子反射到眼镜,在人脑海里形成了对应的颜色。
CLion项目文件位于 samples\classic_lighting\ambient
我躲在房间里,客厅的灯开着。
光从房间门缝里透进来,房间里也有了微弱的光,勉强能看清楚东西。
这是因为光子从门缝进到房间后,会不断反射到房间其他角落。
不过从门缝进到房间的光子比较少,大部分光子在不断反弹耗尽能量后,没有进入到人的眼睛。
仅少部分光子进入眼睛,所以看起来很暗。
晚上到农村去,虽然很暗,但是也不会,伸手看不见五指。
这是因为有少量的光子,从月亮反射到地球,再反射到我们的眼睛。
游戏里实际上也并不会出现纯黑的场景,不然玩家怎么操作。
我们将这种间接的、很微弱的光,称之为环境光。
先来看下这一节实现的效果吧。

自然界的光是由多种波长的光子组成的,可见光也有很多种,不能被物体吸收的光子反射到眼镜,在人脑海里形成了对应的颜色。
在显示器里,其实看到的是模型纹理上的颜色,所以正儿八经来说,模拟的光只要一个强度(intensity)字段就可以了,如下 Environment 结构。
/// 环境配置 class Environment { public: Environment(); private: float ambient_color_intensity_;// 环境颜色强度 };
不过我还是给它加上了一个颜色值,用环境光的颜色值与模型纹理的颜色值相乘。
例如塞尔达血月出现时,场景里所有的物体都要受到影响,带一点红色。

光的颜色、强度,是光的通用属性。
增加了颜色之后, Environment 结构如下:
//file:source/lighting/environment.h /// 环境配置 class Environment { public: Environment(); /// 设置环境颜色 void set_ambient_color(const glm::vec3 &ambient_color){ambient_color_= ambient_color;} /// 获取环境颜色 const glm::vec3 &ambient_color() const{return ambient_color_;} /// 设置环境强度 void set_ambient_color_intensity(float ambient_color_intensity){ambient_color_intensity_ = ambient_color_intensity;} /// 获取环境强度 float ambient_color_intensity() const{return ambient_color_intensity_;} private: glm::vec3 ambient_color_;// 环境颜色 float ambient_color_intensity_;// 环境颜色强度 };
顶点着色器输出顶点数据,片段着色器输出颜色数据。
在片段着色器,将环境光颜色乘以纹理颜色,然后输出。
#version 330 core uniform sampler2D u_diffuse_texture;//颜色纹理 uniform vec3 u_ambient_light_color;//环境光 uniform float u_ambient_light_intensity;//环境光强度 in vec4 v_color;//顶点色 in vec2 v_uv; layout(location = 0) out vec4 o_fragColor; void main() { o_fragColor = texture(u_diffuse_texture,v_uv) * vec4(u_ambient_light_color,1.0) * u_ambient_light_intensity; o_fragColor.a=1.0; }
实例化Environment时设置好颜色,没有特殊要求,这里就是白色:
--file:example/login_scene.lua line:33 function LoginScene:Awake() print("LoginScene Awake") LoginScene.super.Awake(self) self:CreateEnvironment() self:CreateMainCamera() self:CreatePlayer() end --- 环境光设置 function LoginScene:CreateEnvironment() self.environment_=Environment.new() self.environment_:set_ambient_color(glm.vec3(1.0,1.0,1.0)) self.environment_:set_ambient_color_intensity(0.3) end
在Update时,传递到片段Shader中:
--file:example/login_scene.lua line:95 function LoginScene:Update() ...... --设置环境光颜色和强度 self.material_:SetUniform3f("u_ambient_light_color",self.environment_:ambient_color()) self.material_:SetUniform1f("u_ambient_light_intensity",self.environment_:ambient_color_intensity()) ...... end
动手调整环境光的颜色和强度,对比不同效果。
self.environment_:set_ambient_color(glm.vec3(1.0,0.0,0.0))

self.environment_:set_ambient_color(glm.vec3(0.0,1.0,0.0))
