光照
光照使场景更有层次感,使用光照,能建立更真实的三维场景。Orillusion
引擎的光照系统主要由以下几部分组成:
光源 | 说明 |
---|---|
灯光组件 | 基础光源组件:平行光,点光源 和 聚光灯 |
环境反射 | 天空盒环境光,全局曝光 |
全局光照 | 场景中反射或折射的间接光源 |
灯光组件
引擎目前内置了3种经典的光源类型:
平行光
平行光 表示的是光线从以某个方向均匀射出,光线之间是平行的,太阳照射在地球表面的光可以认为是平行光,因为太阳和地球距离的远大于地球半径,所以照射在地球的阳光可以看作是来自同一个方向的光,即平行光。平行光
有 4
个主要个特性:
属性 | 类型 | 说明 |
---|---|---|
lightColor | Color | 灯光的颜色, 默认是白色 rgb(1.0,1.0,1.0) |
intensity | Number | 光照强度,默认值为 1 |
direction | Vector3 | 只读属性,获取平行光的方向向量 |
castShadow | Boolean | 是否开启投影, 默认 false 不开启 |
一般使用平行光所在的 Object3D
的 rotation
控制灯光方向
let lightObj = new Object3D();
scene.addChild(lightObj);
//添加平行光
let dl = lightObj.addComponent(DirectLight);
//设置颜色
dl.lightColor = new Color(1.0, 0.95, 0.84, 1.0);
//设置强度
dl.intensity = 20;
// 通过 Object3D 设置光源的方向
lightObj.rotateX = 45;
lightObj.rotateY = 45;
// 可以通过 direction 获取方向向量
let target = dl.direction
import { BoxGeometry, Camera3D, Engine3D, AtmosphericComponent, LitMaterial, HoverCameraController, MeshRenderer, Object3D, Scene3D, DirectLight, Vector3, webGPUContext, View3D } from '@orillusion/core';
import * as dat from 'dat.gui';
class Sample_Light {
scene: Scene3D;
hoverCameraController: HoverCameraController;
lightObj: any;
constructor() {}
async run() {
await Engine3D.init({
canvasConfig: { devicePixelRatio: 1 }
});
this.scene = new Scene3D();
let cameraObj = new Object3D();
let mainCamera = cameraObj.addComponent(Camera3D);
mainCamera.perspective(37, webGPUContext.aspect, 1, 10000.0);
this.hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController);
this.scene.addChild(cameraObj);
//set camera data
this.hoverCameraController.setCamera(0, -45, 2000);
this.initScene(this.scene);
// add an Atmospheric sky enviroment
this.scene.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
// start render
Engine3D.startRenderView(view);
}
initScene(scene: Scene3D) {
{
let dirLight = new Object3D();
dirLight.rotationX = 30;
dirLight.rotationZ = 30;
let light = dirLight.addComponent(DirectLight);
light.intensity = 20;
light.lightColor.r = 255 / 255;
light.lightColor.g = 157 / 255;
light.lightColor.b = 5 / 255;
scene.addChild(dirLight);
let GUIHelp = new dat.GUI();
GUIHelp.addFolder('Direct Light');
GUIHelp.add(dirLight, 'rotationX', -180, 180, 1);
GUIHelp.add(dirLight, 'rotationY', -180, 180, 1);
GUIHelp.add(dirLight, 'rotationZ', -180, 180, 1);
GUIHelp.addColor({ color: Object.values(light.lightColor).map((v) => v * 255) }, 'color').onChange((v) => {
light.lightColor.copyFromArray(v);
});
GUIHelp.add(light, 'intensity', 0, 100, 1);
}
let mat = new LitMaterial();
mat.baseMap = Engine3D.res.grayTexture;
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(2000, 1, 2000);
mr.material = mat;
this.scene.addChild(floor);
let box = new BoxGeometry(1, 1, 1);
let wall_w = new Object3D();
wall_w.localScale = new Vector3(500, 100, 10);
wall_w.localPosition = new Vector3(0, 50, 0);
let mrw = wall_w.addComponent(MeshRenderer);
mrw.geometry = box;
mrw.material = mat;
this.scene.addChild(wall_w);
let wall_a = new Object3D();
wall_a.localScale = new Vector3(10, 100, 500);
wall_a.localPosition = new Vector3(250, 50, 0);
let mra = wall_a.addComponent(MeshRenderer);
mra.geometry = box;
mra.material = mat;
this.scene.addChild(wall_a);
let wall_d = new Object3D();
wall_d.localScale = new Vector3(10, 100, 500);
wall_d.localPosition = new Vector3(-250, 50, 0);
let mrd = wall_d.addComponent(MeshRenderer);
mrd.geometry = box;
mrd.material = mat;
this.scene.addChild(wall_d);
}
}
new Sample_Light().run();
点光源
点光源 是存在于空间中的一个点,由该点向四面八方发射光线,超过有效距离的地方将无法接受到点光源的光线,并且离光源越远光照强度也会逐渐降低。通常用来模拟生活中常见的灯泡。点光源有主要以下属性:
属性 | 类型 | 说明 |
---|---|---|
lightColor | Color | 灯光的颜色, 默认是白色 rgb(1.0,1.0,1.0) |
intensity | Number | 光照强度,默认值为 1 |
range | Number | 光照最远距离 |
let pointLightObj = new Object3D();
// 设置光源 Object3D 的位置
pointLightObj.x = -10;
pointLightObj.y = 10;
pointLightObj.z = 10;
scene.addChild(pointLightObj);
// 设置点光源组件的半径,强度和颜色
let pointLight = pointLightObj.addComponent(PointLight);
pointLight.range = 20;
pointLight.intensity = 10;
pointLight.lightColor = new Color(1.0, 0.95, 0.84, 1.0);
import { BoxGeometry, Camera3D, Engine3D, AtmosphericComponent, LitMaterial, HoverCameraController, MeshRenderer, Object3D, Scene3D, SphereGeometry, PointLight, Vector3, webGPUContext, View3D } from '@orillusion/core';
import * as dat from 'dat.gui';
class Sample_Light {
scene: Scene3D;
hoverCameraController: HoverCameraController;
lightObj: any;
constructor() {}
async run() {
await Engine3D.init({
canvasConfig: { devicePixelRatio: 1 }
});
this.scene = new Scene3D();
let cameraObj = new Object3D();
let mainCamera = cameraObj.addComponent(Camera3D);
mainCamera.perspective(37, webGPUContext.aspect, 1, 5000.0);
this.hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController);
this.scene.addChild(cameraObj);
//set camera data
this.hoverCameraController.setCamera(0, -45, 1200);
await this.initScene(this.scene);
// add an Atmospheric sky enviroment
this.scene.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
// start render
Engine3D.startRenderView(view);
}
initScene(scene: Scene3D) {
{
let sp = new SphereGeometry(5, 30, 30);
let pointLight = new Object3D();
pointLight.y = 200;
let mr = pointLight.addComponent(MeshRenderer);
mr.geometry = sp;
mr.material = new LitMaterial();
let light = pointLight.addComponent(PointLight);
light.intensity = 100;
light.range = 300;
light.lightColor.r = 255 / 255;
light.lightColor.g = 157 / 255;
light.lightColor.b = 5 / 255;
scene.addChild(pointLight);
let GUIHelp = new dat.GUI();
GUIHelp.addFolder('Direct Light');
GUIHelp.add(pointLight, 'x', -180, 180, 1);
GUIHelp.add(pointLight, 'y', -180, 180, 1);
GUIHelp.add(pointLight, 'z', -180, 180, 1);
GUIHelp.addColor({ color: Object.values(light.lightColor).map((v) => v * 255) }, 'color').onChange((v) => {
light.lightColor.copyFromArray(v);
});
GUIHelp.add(light, 'intensity', 0, 200, 1);
GUIHelp.add(light, 'range', 100, 500, 1);
}
let mat = new LitMaterial();
mat.baseMap = Engine3D.res.grayTexture;
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(2000, 1, 2000);
mr.material = mat;
this.scene.addChild(floor);
let box = new BoxGeometry(1, 1, 1);
let wall_w = new Object3D();
wall_w.localScale = new Vector3(500, 100, 10);
wall_w.localPosition = new Vector3(0, 50, 0);
let mrw = wall_w.addComponent(MeshRenderer);
mrw.geometry = box;
mrw.material = mat;
this.scene.addChild(wall_w);
let wall_a = new Object3D();
wall_a.localScale = new Vector3(10, 100, 500);
wall_a.localPosition = new Vector3(250, 50, 0);
let mra = wall_a.addComponent(MeshRenderer);
mra.geometry = box;
mra.material = mat;
this.scene.addChild(wall_a);
let wall_d = new Object3D();
wall_d.localScale = new Vector3(10, 100, 500);
wall_d.localPosition = new Vector3(-250, 50, 0);
let mrd = wall_d.addComponent(MeshRenderer);
mrd.geometry = box;
mrd.material = mat;
this.scene.addChild(wall_d);
}
}
new Sample_Light().run();
聚光灯
聚光灯 和 点光源
类似,但是它的光线不是朝四面八方发射,而是朝某个方向范围,就像现实生活中的手电筒发出的光。聚光灯有几个主要特性:
属性 | 类型 | 说明 |
---|---|---|
lightColor | Color | 灯光的颜色, 默认是白色 rgb(1.0,1.0,1.0) |
intensity | Number | 光照强度,默认值为 1 |
direction | Vector3 | 只读属性,获取聚光的方向向量 |
range | Number | 光照最远距离 |
innerAngle | Number | 光锥内切角,聚光在小于这个角度的范围内有光线 |
outerAngle | Number | 光锥外切角,光线会在内切角到外切角的范围内逐步衰减到0 |
let spotLightObj = new Object3D();
// 设置光源 Object3D 的位置
spotLightObj.y = 100;
spotLightObj.rotationX= 90;
scene.addChild(spotLightObj);
// 设置聚光灯组件的属性
let spotLight = spotLightObj.addComponent(SpotLight);
spotLight.lightColor = new Color(1.0, 0.95, 0.84, 1.0);
spotLight.intensity = 20;
spotLight.range = 200;
spotLight.innerAngle = 20;
spotLight.outerAngle = 35;
import { BoxGeometry, Camera3D, Engine3D, AtmosphericComponent, LitMaterial, HoverCameraController, MeshRenderer, Object3D, Scene3D, SphereGeometry, SpotLight, Vector3, webGPUContext, View3D } from '@orillusion/core';
import * as dat from 'dat.gui';
class Sample_Light {
scene: Scene3D;
hoverCameraController: HoverCameraController;
lightObj: any;
constructor() {}
async run() {
await Engine3D.init({
canvasConfig: { devicePixelRatio: 1 }
});
this.scene = new Scene3D();
let cameraObj = new Object3D();
let mainCamera = cameraObj.addComponent(Camera3D);
mainCamera.perspective(37, webGPUContext.aspect, 1, 5000.0);
this.hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController);
this.scene.addChild(cameraObj);
//set camera data
this.hoverCameraController.setCamera(0, -45, 1000);
this.initScene(this.scene);
// add an Atmospheric sky enviroment
this.scene.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
// start render
Engine3D.startRenderView(view);
}
initScene(scene: Scene3D) {
{
let sp = new SphereGeometry(5, 30, 30);
let spotLight = new Object3D();
let mr = spotLight.addComponent(MeshRenderer);
mr.geometry = sp;
mr.material = new LitMaterial();
let light = spotLight.addComponent(SpotLight);
spotLight.y = 200;
spotLight.z = 50;
spotLight.rotationX = 120;
light.lightColor.r = 255 / 255;
light.lightColor.g = 157 / 255;
light.lightColor.b = 5 / 255;
light.intensity = 100;
light.range = 500;
light.outerAngle = 110;
light.innerAngle = 30;
scene.addChild(spotLight);
let GUIHelp = new dat.GUI();
GUIHelp.addFolder('Direct Light');
GUIHelp.add(spotLight, 'x', -180, 180, 1);
GUIHelp.add(spotLight, 'y', -180, 180, 1);
GUIHelp.add(spotLight, 'z', -180, 180, 1);
GUIHelp.add(spotLight, 'rotationX', -180, 180, 1);
GUIHelp.add(spotLight, 'rotationY', -180, 180, 1);
GUIHelp.add(spotLight, 'rotationZ', -180, 180, 1);
GUIHelp.addColor({ color: Object.values(light.lightColor).map((v) => v * 255) }, 'color').onChange((v) => {
light.lightColor.copyFromArray(v);
});
GUIHelp.add(light, 'intensity', 0, 200, 1);
GUIHelp.add(light, 'range', 100, 1000, 1);
GUIHelp.add(light, 'outerAngle', 0, 180, 1);
GUIHelp.add(light, 'innerAngle', 0, 100, 1);
}
let mat = new LitMaterial();
mat.baseMap = Engine3D.res.grayTexture;
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(2000, 1, 2000);
mr.material = mat;
this.scene.addChild(floor);
let box = new BoxGeometry(1, 1, 1);
let wall_w = new Object3D();
wall_w.localScale = new Vector3(500, 100, 10);
wall_w.localPosition = new Vector3(0, 50, 0);
let mrw = wall_w.addComponent(MeshRenderer);
mrw.geometry = box;
mrw.material = mat;
this.scene.addChild(wall_w);
let wall_a = new Object3D();
wall_a.localScale = new Vector3(10, 100, 500);
wall_a.localPosition = new Vector3(250, 50, 0);
let mra = wall_a.addComponent(MeshRenderer);
mra.geometry = box;
mra.material = mat;
this.scene.addChild(wall_a);
let wall_d = new Object3D();
wall_d.localScale = new Vector3(10, 100, 500);
wall_d.localPosition = new Vector3(-250, 50, 0);
let mrd = wall_d.addComponent(MeshRenderer);
mrd.geometry = box;
mrd.material = mat;
this.scene.addChild(wall_d);
}
}
new Sample_Light().run();
IES 灯光信息
照明工程学会(IES)定义了一种文件格式,可以描述真实灯光在现实世界的光照强度分布情况。IES 文件描述了各种类型的灯具的光线强弱度,衰减曲线,模拟灯珠的透射,折射等光线变化行为,最终解码成指定的2D数据图进行3D空间的灯光映射。
IES 灯光示例
加载 IES 贴图
除了常规的光源类型设置,引擎还支持通过加载预设的 IES
贴图来设置复杂的光线分布:
// 加载 IES 贴图
let iesTexture = await Engine3D.res.loadTexture("https://cdn.orillusion.com/ies/ies_2.png");
// 创建 IES 对象
let iesPofiles = new IESProfiles();
iesPofiles.IESTexture = iesTexture;
let light = new Object3d()
let pointLight = light.addComponent(PointLight);
// 设置灯光 IES 分布
pointLight.iesPofile = iesPofiles;
import { BoxGeometry, Camera3D, Engine3D, View3D, LitMaterial, HoverCameraController, BitmapTexture2D, MeshRenderer, Object3D, Scene3D, SphereGeometry, PointLight, Vector3, webGPUContext, IESProfiles, AtmosphericComponent } from '@orillusion/core';
class Sample_LightIES {
scene: Scene3D;
hoverCameraController: HoverCameraController;
lightObj: any;
constructor() {}
async run() {
Engine3D.setting.shadow.pointShadowBias = 0.0001;
Engine3D.setting.shadow.type = `HARD`;
await Engine3D.init({
canvasConfig: { devicePixelRatio: 1 }
});
this.scene = new Scene3D();
let cameraObj = new Object3D();
let mainCamera = cameraObj.addComponent(Camera3D);
mainCamera.perspective(37, webGPUContext.aspect, 1, 5000.0);
this.hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController);
this.scene.addChild(cameraObj);
//set camera data
this.hoverCameraController.setCamera(0, -45, 200);
await this.initScene(this.scene);
// add an Atmospheric sky enviroment
this.scene.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
// start render
Engine3D.startRenderView(view);
}
async initScene(scene: Scene3D) {
// load ies texture
let iesTexture = await Engine3D.res.loadTexture('https://cdn.orillusion.com/ies/ies_2.png');
var iesPofiles = new IESProfiles();
iesPofiles.IESTexture = iesTexture;
{
let po = new Object3D();
let pl = po.addComponent(PointLight);
pl.intensity = 10;
pl.range = 100;
pl.castShadow = true;
pl.realTimeShadow = true;
pl.iesProfiles = iesPofiles;
po.x = 0;
po.y = 22;
po.z = 15;
this.scene.addChild(po);
}
let ball: Object3D;
{
let mat = new LitMaterial();
mat.roughness = 0.5;
mat.metallic = 0.2;
ball = new Object3D();
let mr = ball.addComponent(MeshRenderer);
mr.geometry = new SphereGeometry(6, 20, 20);
mr.material = mat;
this.scene.addChild(ball);
ball.transform.x = -17;
ball.transform.y = 10;
ball.transform.z = 10;
//wall
let back_wall = new Object3D();
let mr2 = back_wall.addComponent(MeshRenderer);
mr2.geometry = new BoxGeometry(500, 500, 10);
mr2.material = mat;
this.scene.addChild(back_wall);
}
}
}
new Sample_LightIES().run();
获取 IES 贴图
社区中有大量优质的 IES
资源分享社区,一些灯光设备厂商也会分享专业的 IES
文件,它们一般都是免费的,比如:
社区中同样有很多专业的 IES
预览/转换的软件,比如 IESviewer,您也可以使用专业的3D建模软件来将 IES
文件转换到普通的 png
贴图文件,最后加载到引擎中来。
环境光
除了直接的光源,引擎通过设置 Scene3D.evnMap
天空盒贴图进行基本的环境光渲染,详情参考 天空盒 相关介绍
全局光照
一般光照系统只考虑光源直接照射到物体表面所产生的效果,不会计算光源经过物体表面反射或折射的光线,即间接光照。全局光照系统能够对间接光照进行建模,实现更加逼真的光线效果。详情参考 高级 GI