全网最详Babylon.js入门教材(5)-设置光源

138 篇文章 1 订阅
138 篇文章 2 订阅

Q:Babylon.js是什么?🤔️

Babylon.js 是一个强大的、开源的、基于 WebGLWebGPU3D引擎,用于在网页上创建和渲染 3D图形。它提供了一套丰富的 API和功能,包括物理引擎、粒子系统、骨骼动画、碰撞检测、光照和阴影等,可以帮助开发者快速创建复杂的 3D场景和交互。

Q:我为什么要写该系列的教材? 🤔️

因为公司业务的需要因而要在项目中使用到 Babylon.js,虽然官方的文档看起来覆盖面都挺全,且 playgroud 上的案例也都比较多,但一些具体的 API 或者功能属性也都没有特别多详细的介绍,包括很多使用方式的很多坑都得自己去源码中或者论坛上找。在将其琢磨完之后, 决定写一系列关于它的教材来帮助更多 babylon.js的使用者或者是期于学习 Web 3D的开发者。同时也是自己对其的一种巩固。

Babylon.js中的光源类型

学习完了上一章的材质之后,再学习光源,应该会亲切很多,因为在那章里,我们无形中已经学习过很多光源了。

这一章节,我们先来学习 Babylon.js 中主要的几种光源类型,了解它们的基础用法和各自的特性,然后再来看几个由不同光组合而成的有趣的案例。

Babylon.js中主要有以下四个种类的光源:

  • Point Light:点光源
  • Directional Light:定向光
  • Spot Light: 聚光灯
  • Hemispheric Light:半球光

类型其实也不是很多,但是能应对大部分场景。关于它们共有的特性和属性,我们可以到 Babylon.js 的源码中找一找答案。

在源码中,有一个名为 Light 和名为 ShadowLight 的类。

Light 类是所有灯光的基类,其中包含了很多所有灯光都有的(或者说是通用)的属性,常见的例如:

diffuse类型为 Color3,默认值为白色,表示漫反射的颜色
specular类型为 Color3,默认值为白色,表示高光在物体上产生高光的颜色
intensity类型为浮点数,默认值为 1.0,表示光的强度
range类型为数字,默认值为 Number.MAX_VALUE。定义在场景单位中距离光源的影响距离

ShadowLight类继承至 Light 类,从命名上也可以看出来,ShadowLight应该是表示那些会产生阴影效果的光源。例如点光源(PointLight)、定向光(DirectionalLight)、聚光灯(SpotLight),而 HemisphericLight 是不继承 ShadowLight 的。

所以所有继承 ShadowLight 的光源,都有一个 shadowEnabled 属性用于控制是否启用阴影(默认为 true)。

以上灯光类的类图关系如下:

点光源 PointLight

点光源从一个点,向所有方向发出光线。它的光线强度会随着距离的增加而衰减。一个非常有代表性的使用场景就是模拟灯泡、火把

PointLight类的初始化定义:

 

typescript

代码解读

复制代码

/** * 创建一个 PointLight 对象,并将其添加到场景中。 * 文档:https://doc.babylonjs.com/features/featuresDeepDive/lights/lights_introduction * @param name 光源的名称 * @param position 点光源在场景中的位置 * @param scene 光源所属的场景 */ constructor( name: string, position: Vector3, scene?: Scene ) {}

点光源基础案例

点光源的案例:

 

typescript

代码解读

复制代码

// 创建点光源,并设置漫反射光和高光 var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 1, 0), scene); light.diffuse = new BABYLON.Color3(1, 0, 0); // 红色 light.specular = new BABYLON.Color3(0, 1, 0); // 绿色 // 创建一个球体 var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene); sphere.position.z = 1;

案例中,创建一个点光源并让它照射在球体上,通过学习【材质与光的交响曲】我们知道,没给物体设置材质的话,默认会反射所有照射到它身上的光,因此效果为:

官网Playground链接查看:playground.babylonjs.com/#20OAV9

上面的案例,你会发现除了灯光的 diffuse 漫反射属性,还有 specular 高光属性。诶~这个属性是不是觉得很眼熟,因为材质上也有设置高光样式的 specularColorspecularTexture

两者的区别也很好理解,灯光的 specular 决定了光源发出的高光颜色,影响所有被该光照亮的物体的高光颜色。

而材质上的 specularColor 决定了物体表面反射高光的颜色,仅影响应用了该材质的物体,它们共同作用来决定物体表面的高光效果。

展示点光源是个“点”的案例

上面的案例可能不太看的出来点光源是一个点的效果,让我们来下面的这个:

将点光源的位置设置在世界坐标原点中心(0, 0, 0),然后分别在其上下左右都增加一个小球,代码如下:

 

typescript

代码解读

复制代码

var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 0, 0), scene); light.diffuse = new BABYLON.Color3(1, 0, 0); light.specular = new BABYLON.Color3(0, 1, 0); var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene); sphere.position.y = 2; var sphere2 = BABYLON.MeshBuilder.CreateSphere("sphere2", {}, scene); sphere2.position.y = -2; var sphere3 = BABYLON.MeshBuilder.CreateSphere("sphere3", {}, scene); sphere3.position.x = 2; var sphere4 = BABYLON.MeshBuilder.CreateSphere("sphere4", {}, scene); sphere4.position.x = -2;

最终的效果如下:

展示点光源是个“点”的案例二

另一个案例,我们在中心创建一个小球,还有一个地板:

 

typescript

代码解读

复制代码

var scene = new BABYLON.Scene(engine); var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); // 灯光 var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 1, 0), scene); light.diffuse = new BABYLON.Color3(1, 0, 0); // 设置漫反射为红色 light.specular = new BABYLON.Color3(0, 1, 0); // 设置高光为绿色 // 球 var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene); // 地板 var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 4, height: 6}, scene);

效果如下:

靠近中间的地方会更亮,越边缘越暗,并且高光处也是我们设置的绿色。

平行光 DirectionalLight

DirectionalLight用于模拟来自无限远处的平行光线,类似于太阳光。它在场景中提供均匀的光照效果,适用于模拟大面积的光源

它的主要属性除了公共的 diffusespecularintensity 以外,还有 diection 用于指定光源的方向,决定光线的照射方向。

DirectionalLight类的初始化参数为:

 

typescript

代码解读

复制代码

/** * 在场景中创建一个 DirectionalLight 对象,朝向传递的方向(Vector3)。 * 平行光源从所有地方向给定方向发出光线。 * 它可以投射阴影。 * 文档: https://doc.babylonjs.com/features/featuresDeepDive/lights/lights_introduction * @param name 光源的名称 * @param direction 光的方向 * @param scene 光源所属的场景 */ constructor( name: string, direction: Vector3, scene?: Scene ) {}

展示平行光是平行的案例

我们还是以上面点光源的第三个案例来做对比,创建一个小球和一个地板,看看会有什么不同的效果。

案例代码:

 

typescript

代码解读

复制代码

var scene = new BABYLON.Scene(engine); var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); // 创建平行光,且光线方向垂直朝下 var light = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0, -1, 0), scene); light.diffuse = new BABYLON.Color3(1, 0, 0); // 设置漫反射为红色 light.specular = new BABYLON.Color3(0, 1, 0); // 设置高光为绿色 // 球 var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene); // 地板 var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 4, height: 6}, scene);

效果如下:

可以看到,相机视角垂直向下看的时候,除了高光处向四周有从黄到红的过程,其它视角在地板上的漫反射光照都是差不多的,都呈现出红色。

另外还有一点要注意,并不是说平行光就不会产生阴影效果,可以看到上面的小球也是会有阴影效果的。

聚光灯 SpotLight

SpotLight是 Babylon.js 中的一种聚光灯光源,模拟现实世界中的聚光灯效果。它从一个点发出光束,并在特定方向上逐渐扩散,形成一个锥形光束。SpotLight非常适合用于模拟舞台灯光、手电筒等场景

对比与平行光,它多了一个 position 属性,用于定义光源的位置,同时它也有 direction 光束的方向属性。

再就是有一些关于“聚光”效果的属性,例如:

angle:光束的角度,以弧度表示。决定了光束的扩散范围。

 

typescript

代码解读

复制代码

light.angle = Math.PI / 3; // 60度

exponent: 光束的衰减系数。值越大,光束边缘越柔和。

 

typescript

代码解读

复制代码

light.exponent = 2;

SpotLight 类的初始化参数为:

 

typescript

代码解读

复制代码

/** * 在场景中创建一个 SpotLight 对象。聚光灯是一个简单的定向光锥。 * 它可以投射阴影。 * 文档: https://doc.babylonjs.com/features/featuresDeepDive/lights/lights_introduction * @param name 光源的名称 * @param position 聚光灯在场景中的位置 * @param direction 光在场景中的方向 * @param angle 光锥的角度(以弧度表示) * @param exponent 光从发射点开始的衰减速度 * @param scene 光源所属的场景 */ constructor( name: string, position: Vector3, direction: Vector3, angle: number, exponent: number, scene?: Scene ) {}

聚光灯的基础案例

来看一个基础的案例:

定义了两个聚光灯,同时修改它们的 diffusespecular 属性。

 

typescript

代码解读

复制代码

var scene = new BABYLON.Scene(engine); var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 4, 5, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); // 光的方向是从一个位置直接向下一个单位向上,衰减缓慢 var light = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(-1, 1, -1), new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 10, scene); light.diffuse = new BABYLON.Color3(1, 0, 0); light.specular = new BABYLON.Color3(0, 1, 0); // 光的方向是从一个位置直接向下一个单位向上,衰减快 var light1 = new BABYLON.SpotLight("spotLight1", new BABYLON.Vector3(1, 1, 1), new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 50, scene); light1.diffuse = new BABYLON.Color3(0, 1, 0); light1.specular = new BABYLON.Color3(0, 1, 0); var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 4, height: 4}, scene);

效果如下:

官网案例地址:playground.babylonjs.com/#20OAV9#3

半球光 HemisphericLight

HemisphericLightBabylon.js 中的一种半球光源,模拟从天空和地面反射的环境光。它从一个方向发出光线,并且有一个对立方向的环境光,适用于模拟自然光照效果。

这里提到的对立方向的环境光是什么意思呢?指的是它的特有属性 groundColor: 地面反射光的颜色,影响物体表面未被直接光照射部分的颜色。在等会的案例中就能看到它发挥的作用了。

HemisphericLight 类的初始化参数为:

 

typescript

代码解读

复制代码

/** * 根据传入的方向(Vector3)在场景中创建一个HemisphericLight对象。 * 该对象模拟环境光,因此传入的方向是光的反射方向,而不是入射方向。 * HemisphericLight不能投射阴影。 * 文档:https://doc.babylonjs.com/features/featuresDeepDive/lights/lights_introduction * @param name 灯光的名称 * @param direction 灯光反射的方向 * @param scene 灯光所属的场景 */ constructor( name: string, direction: Vector3, scene?: Scene ) {}

半球光的基础案例

定义一个球,同时设置一个半球光,设置它的漫反射与高光、还有地面反射光颜色:

 

typescript

代码解读

复制代码

var scene = new BABYLON.Scene(engine); var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 4, 5, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); // 光的方向是向上和向左 var light = new BABYLON.HemisphericLight("hemiLight", new BABYLON.Vector3(-1, 1, 0), scene); light.diffuse = new BABYLON.Color3(1, 0, 0); light.specular = new BABYLON.Color3(0, 1, 0); light.groundColor = new BABYLON.Color3(0, 1, 0); var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene);

效果如下:

可以看到,这个球的上半部分是被反射成了红色,也就是 diffuse 的颜色,另外一部分,靠近地面的部分被反射成了绿色,这就是 groundColor 的作用,你可以理解为它是来自相反方向的光。

官方案例地址:playground.babylonjs.com/#20OAV9#5

材质对光的限制

这部分直接看材质那一篇文章即可:材质对光的限制 maxSimultaneousLights

开光灯 setEnabled()

使用灯上的 setEnabled()方法即可:

 

typescript

代码解读

复制代码

light.setEnabled(false); // 关灯 light.setEnabled(true); // 开灯

调节灯光强度及到达距离

强度 intensity

灯光强度的调节直接设置 intensity 即可:

intensity的默认值是 1。

 

typescript

代码解读

复制代码

light0.intensity = 0.5; // 调暗 light1.intensity = 2.4; // 调亮

到达的距离 range

对于点光源和聚光灯,还可以使用 range 属性设置光线到达的距离,例如:

默认值为 Number.MAX_VALUE,即 JS 中数字的最大值。

 

typescript

代码解读

复制代码

light.range = 100;

案例练习

灯光案例一

实现以下效果:

提示:半球光、diffusespeculargroundColorambientColor

------------------------------- 分割线 -------------------------------

在线预览地址:

playground.babylonjs.com/#20OAV9#14

代码实现:

 

typescript

代码解读

复制代码

var scene = new BABYLON.Scene(engine); var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 4, 5, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); scene.ambientColor = new BABYLON.Color3(1, 1, 1); //Light direction is up and left var light = new BABYLON.HemisphericLight("hemiLight", new BABYLON.Vector3(-1, 1, 0), scene); light.diffuse = new BABYLON.Color3(1, 0, 0); light.specular = new BABYLON.Color3(0, 1, 0); light.groundColor = new BABYLON.Color3(0, 1, 0); var redMat = new BABYLON.StandardMaterial("redMat", scene); redMat.ambientColor = new BABYLON.Color3(1, 0, 0); var greenMat = new BABYLON.StandardMaterial("redMat", scene); greenMat.ambientColor = new BABYLON.Color3(0, 1, 0); //No ambient color var sphere0 = BABYLON.MeshBuilder.CreateSphere("sphere0", {}, scene); sphere0.position.x = -1.5; //Red Ambient var sphere1 = BABYLON.MeshBuilder.CreateSphere("sphere1", {}, scene); sphere1.material = redMat; //Green Ambient var sphere2 = BABYLON.MeshBuilder.CreateSphere("sphere2", {}, scene); sphere2.material = greenMat; sphere2.position.x = 1.5;

灯光案例二

实现以下效果:

提示词:聚光灯、diffuse

------------------------------- 分割线 -------------------------------

在线预览地址:

playground.babylonjs.com/#20OAV9#9

代码实现:

 

typescript

代码解读

复制代码

var scene = new BABYLON.Scene(engine); var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 4, 5, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); //red light var light = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(-Math.cos(Math.PI/6), 1 , -Math.sin(Math.PI/6)), new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 1.5, scene); light.diffuse = new BABYLON.Color3(1, 0, 0); //green light var light1 = new BABYLON.SpotLight("spotLight1", new BABYLON.Vector3(0, 1, 1 - Math.sin(Math.PI / 6)), new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 1.5, scene); light1.diffuse = new BABYLON.Color3(0, 1, 0); //blue light var light2 = new BABYLON.SpotLight("spotLight2", new BABYLON.Vector3(Math.cos(Math.PI/6), 1, -Math.sin(Math.PI/6)), new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 1.5, scene); light2.diffuse = new BABYLON.Color3(0, 0, 1); var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 4, height: 4}, scene);

原文链接:https://juejin.cn/post/7417665616494198836

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值