本文深入解析Three.js光照模块源码,涵盖Light基类及AmbientLight、DirectionalLight、PointLight、SpotLight等具体光源类的实现细节。重点分析position、intensity、distance等关键属性的作用,以及阴影控制参数castShadow和onlyShadow的逻辑。同时简要探讨Particle与ParticleSystem类的结构,揭示场景定义中光照与粒子的基础构建方式。
随着气温降低,人的惰性也随之增加,更倾向于待在温暖的室内进行娱乐活动。由于长时间未深入研读Three.js源码,今日趁天气晴好,决定继续推进阅读计划。
Three.js光照系统概述与Light基类
本次阅读聚焦于光照模块。从光线传播的角度来看,光照类型主要包括环境光、平行光和点光源;而从物体表面材质的响应角度来看,则涉及漫反射和镜面反射两种主要反射模型。
Lights:Light
相关实现代码如下:
THREE.Light = function ( hex ) {
THREE.Object3D.call( this );
this.color = new THREE.Color( hex );
}; 该类作为其他光照对象的原型或基类,直接继承自Object3D。其内部仅包含一个THREE.Color类型的color属性,用于定义光源颜色,这一设计符合直观逻辑。
在Three.js架构中,光照被视为一种特殊的Object3D对象。通过Scene.add()方法将光照对象加入场景后,渲染器会自动处理并渲染所添加的光照效果。
Light::AmbientLight
相关实现代码如下:
THREE.AmbientLight = function ( hex ) {
THREE.Light.call( this, hex );
}; 环境光(AmbientLight)属于无方向性的光源。该类并未在Light基础上增加新的属性或方法,其存在主要为了语义上的继承关系。从功能必要性来看,它甚至无需继承自Object3D。
Light::DirectionalLight
环境光与环境光类实现
相关实现代码如下:
THREE.DirectionalLight = function ( hex, intensity ) {
THREE.Light.call( this, hex );
this.position = new THREE.Vector3( 0, 1, 0 );
this.target = new THREE.Object3D();
this.intensity = ( intensity !== undefined ) ? intensity : 1;
this.castShadow = false;
this.onlyShadow = false;
// more settings about shadow ......
}; 平行光属性与阴影控制机制
平行光(DirectionalLight)具有明确的方向性。构造该函数时需传入颜色hex及光线密度intensity。该类包含以下关键属性:
position:定义光源位置,光线方向由该位置指向原点。
intensity:表示光线密度,默认值为1。由于RGB值范围限制在0~255之间,无法直接反映光照强度的细微变化,因此引入此属性以体现光照越强、物体表面越明亮的效果。
distance:衰减距离,默认值为0,表示光照无衰减。若设为非0值,光照将从position所在位置(实际为position所在的平面)开始衰减,当距离超过distance时,光照强度intensity降为0。
castShadow:布尔值,控制是否生成阴影,默认false。若设为true,系统将对所有表面逐像素计算其在光照方向上的遮挡情况,这将消耗大量计算资源。
onlyShadow:布尔值,控制是否仅生成阴影而不照亮物体,默认false。此模式可能适用于某些特殊应用场景。
shadowCameraLeft、shadowCameraRight等属性系列,用于以position点为中心控制阴影生成的范围。
shadowBias:阴影偏移量,默认值为0。
shadowDarkness:阴影对物体亮度的影响程度,取值范围0~1,默认值为0.5。
此外还存在若干属性,其具体含义尚不明确(需补充计算机图形学知识以进一步理解,暂且继续阅读)。
Light::PointLight
相关实现代码如下:
THREE.PointLight = function ( hex, intensity, distance ) {
THREE.Light.call( this, hex );
this.position = new THREE.Vector3( 0, 0, 0 );
this.intensity = ( intensity !== undefined ) ? intensity : 1;
this.distance = ( distance !== undefined ) ? distance : 0;
}; 点光源与平行光位置差异分析
点光源(PointLight)的position属性即代表光源的具体坐标点。需注意点光源与平行光在position默认值上的区别:点光源默认位于原点,而平行光默认位于(0, 1, 1),这使得默认平行光的方向与相机默认朝向一致。
其余两个属性与平行光保持一致。PointLight点光源未包含关于如何生成阴影的具体设定。
Light::SpotLight
相关实现代码如下:
THREE.SpotLight = function ( hex, intensity, distance, angle, exponent ) {
THREE.Light.call( this, hex );
this.position = new THREE.Vector3( 0, 1, 0 );
this.target = new THREE.Object3D();
this.intensity = ( intensity !== undefined ) ? intensity : 1;
this.distance = ( distance !== undefined ) ? distance : 0;
this.angle = ( angle !== undefined ) ? angle : Math.PI / 2;
this.exponent = ( exponent !== undefined ) ? exponent : 10; // more settings about shadow...
}; 聚光灯参数与材质影响
聚光灯(SpotLight)是一种能在特定方向上产生阴影的点光源,主要影响MeshLambertMaterial和MeshPhongMaterial类型材质的表面表现。其阴影处理设定与DirectionLight一致。
综上所述,光照对象本身并不承担实际的渲染任务,其核心职责仅在于定义光照的渲染规则与参数。
Object::Partical
相关实现代码如下:
THREE.Particle = function ( material ) {
THREE.Object3D.call( this );
this.material = material;
}; 粒子系统与粒子类结构解析
粒子(Particle)本质上是一个由材质定义的Object3D对象。Object3D提供坐标(即粒子位置)并负责粒子的运动逻辑,而粒子本身仅需指定用于表现其外观的材质即可。
Object::ParticalSystem
相关实现代码如下:
THREE.ParticleSystem = function ( geometry, material ) {
THREE.Object3D.call( this );
this.geometry = geometry;
this.material = ( material !== undefined ) ? material : new THREE.ParticleBasicMaterial( { color: Math.random() * 0xffffff } );
this.sortParticles = false;
if ( this.geometry ) {
if( this.geometry.boundingSphere === null ) {
this.geometry.computeBoundingSphere();
}
this.boundRadius = geometry.boundingSphere.radius;
}
this.frustumCulled = false;
}; 粒子系统(ParticleSystem)用于表现多个粒子的运动,其本身继承自Object3D。该类包含以下关键属性:
geometry属性:定义每个节点为一个粒子,这些粒子共享同一材质。
material属性:定义这些节点所使用的材质。
frustumCulled属性:布尔值,若设为true,则剔除相机视锥体外的粒子。具体逻辑尚不明确:是当粒子系统中心坐标在视锥体外时剔除整个系统,还是单个粒子出界即被剔除?推测后者可能性较大。
前述内容主要涉及场景的定义方式,至于场景的具体渲染机制较难深入。接下来计划通过Demo代码结合WebGLRenderer类的源代码(数千行代码)进行进一步学习。