Orillusion

    • 注册
    • 登录
    • 搜索
    • 版块
    • 最新
    • 标签

    orillusion入门系列五 | 光照01

    中文社区
    orillusion引擎 engine
    1
    1
    135
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • O
      oldguy 最后由 编辑

      回忆一下过去的学习过程,场景开辟了一处空间,可以作为容器,几何体使空间中有了物体,物体具有一些典型的形状,材质使物体得到了美化和更有真实感,今天按照惯例应该到光照了。没有光我们看不到任何物体,渲染的工作主要在对于光的处理上。
      光是由光源发出的,光在传播的过程中会经过物体的反射、折射、漫反射等多种变化,而反射回去的光又会反复的物体间反射,反射的过程中还会产生阴影,所以这是一个非常复杂的过程。我们从典型的光源组件开始,由浅入深的使用 orillusion 引擎尝试下对光的操作。

      光源组件

      观察我们的生活环境我们被各种光包围,orillusion封装了常见的三种光源组件,使用时创建 Object3D类型的对象,然后将光源组件添加至刚创建的对象中,就可以实现典型的光源效果。
      光源组件的用法可以参照以下示例:
      // 创建对象,对象是组件的容器

      let obj= new Object3D();
      // 将对象添加至场景
      scene.addChild(obj);
      // 添加一个光源组件至对象中,我们这里以平行光为例
      let light= obj.addComponent(DirectLight);
      

      平行光

      光顾名思义平行光是一种光线的角度相同,不同位置的光照强度相机的光,自然界中最常见到的平行光源是太阳。在场景中为了影响整体的光影效果,一般引擎会提供平行光功能。
      平行光一般具有以下的参数:

      • lightColor(光照颜色): 每个平行光都必须有一定颜色,这里如果不指定会又白色作为默认颜色,需要注意的是目标物体所呈现出来的颜色还和物体本身的材质有关。
      • intensity(光照强度):用来调节光线的强弱,毫无疑问光线强度越大光线越充足,越弱则越暗,如果完全没有光,场景内将陷入黑暗,通常除了光源还会有环境光,所以默认情况下不会是漆黑一片。
      • castShadow(开启阴影):只有开启阴影的光才会产生阴影,同时接收阴影的物体本身也要打开对应的参数才能看到阴影效果。
      • 方向:这不是平行光本身的参数了,这里必须要强调一点,平行光是有方向的,平行光的方向是由组件所对应的对象调节的,对象本身的旋转属性(rotationX、rotationY、rotationZ),用来调节对象所包含的光照组件方向,下面点光源和聚光灯类似。
        这里罗列一下关键的代码:
      // 创建一个容器对象
      let lightObj = new Object3D();
      //类中声明一个光源对象,这里初始化组件实例
      this.directLight = lightObj.addComponent(DirectLight);
      // 为了观察效果,打开了阴影
      this.directLight.castShadow = true;
      // 将对象添加到场景中
      this.scene.addChild(lightObj);
      
      // 定义了调整的参数结构
      const lightInfo = {
          intensity:1.0,
          rotationX:0,
          rotationY:0,
          rotationZ:0,
          lightColor:'#fff',
      }
      // 这里使用data.gui来实现界面效果
      let lightFolder = gui.addFolder("Light");
      // 强度直接修改
      lightFolder.add(lightInfo, "intensity", 0, 10).step(0.1).onChange((v) => {
          console.log('intensity:', v);
          this.directLight.intensity = v;
      });
      lightFolder.add(lightInfo, "rotationX", -360, 360).onChange((v) => {
          console.log('rotationX:', v);
          this.directLight.transform.rotationX = v;
      });
      lightFolder.add(lightInfo, "rotationY", -360, 360).onChange((v) => {
          console.log('rotationY:', v);
          this.directLight.transform.rotationY = v;
      });
      lightFolder.add(lightInfo, "rotationZ", -360, 360).onChange((v) => {
          console.log('rotationZ:', v);
          this.directLight.transform.rotationZ = v;
      });
      lightFolder.addColor(lightInfo, "lightColor").onChange((v) => {
          console.log('lightColor:', v);
          let color: Color = new Color();
          color.setHex(v);
          this.directLight.lightColor = color;
      });
      

      修改完后可以在 canary 中直接运行,查看效果如下:
      2338c3cc-7ee6-46c2-b46b-3e2c27321021-image.png
      这个示例里面除了我们重点关注的平行光以外,还有阴影,反射等等,下面会一一介绍。使用思路仍然是通过熟悉 orilluson 的api,调用不同的接口与参数即可。
      这里可以看到,没有做位置的变换操作,在当前的版本调整位置是没有效果的,调整强度参数能够看到光线的强度随着数值而动态变化。

      点光源

      有了前面最好理解的平行光作为铺垫我们已经熟悉了光源对象的使用,点光源就是另种特性的光源,类似于萤火虫、没有灯罩的白炽灯这样的发光体,本身是一个点,向四面八方发射光线。
      点光源有更多的属性,除了平行光的属性外,罗列一下点光源所特有的属性:

      • range(距离):从光源到光线衰减到0的最远距离,该值越大能够发出光线受到影响的范围越大。
      • radius(半径):光照的最亮那部分的半径。
      • at(衰减系数):光照的效果根据系数有所衰减。
      • 位置:点光源由于受距离的影响,不同距离显示的效果不同,所以位置起着重要的作用。与平行光的旋转类似,点光源的位移是由对应的对象所控制。
        点光源的调用关键代码如下:
      // 创建一个光源对象
      let lightObj = new Object3D();
      
      // 由于点光源的位置影响光照效果,所以附加一个球形物体用来标记位置 
      let mr = lightObj.addComponent(MeshRenderer);
      mr.geometry = new SphereGeometry(0.5, 10, 10);;
      mr.material = new HDRLitMaterial();
      
      //创建点光源组件
      this.lightLight = lightObj.addComponent(PointLight);
      // 打开阴影效果
      this.lightLight.castShadow = true;
      // 光源对象添加到场景
      this.scene.addChild(lightObj);
      // 设置光源的位置 
      lightObj.y = 10;
      
      // 点光源可以使用的参数
      const lightInfo = {
          intensity:1.0,
          range:0,
          radius:0,
          at:0,
          x:0,
          y:0,
          z:0,
          rotationX:0,
          rotationY:0,
          rotationZ:0,
          lightColor:'#fff',
      }
      
      // 对各参数进行设置
      let lightFolder = gui.addFolder("Light");
      lightFolder.add(lightInfo, "intensity", 0, 10).step(0.1).onChange((v) => {
          console.log('intensity:', v);
          this.lightLight.intensity = v;
      });
      lightFolder.add(lightInfo, "range", 0, 10).step(0.1).onChange((v) => {
          console.log('range:', v);
          this.lightLight.range = v;
      });
      lightFolder.add(lightInfo, "radius", 0, 10).step(0.1).onChange((v) => {
          console.log('radius:', v);
          this.lightLight.radius = v;
      });
      lightFolder.add(lightInfo, "at", 0, 10).step(0.1).onChange((v) => {
          console.log('at:', v);
          this.lightLight.at = v;
      });
      lightFolder.add(lightInfo, "x", -10, 10).onChange((v) => {
          console.log('x:', v);
          this.lightLight.transform.x = v;
      });
      lightFolder.add(lightInfo, "y", -10, 10).onChange((v) => {
          console.log('y:', v);
          this.lightLight.transform.y = v;
      });
      lightFolder.add(lightInfo, "z", -10, 10).onChange((v) => {
          console.log('z:', v);
          this.lightLight.transform.z = v;
      });
      lightFolder.add(lightInfo, "rotationX", -360, 360).onChange((v) => {
          console.log('rotationX:', v);
          this.lightLight.transform.rotationX = v;
      });
      lightFolder.add(lightInfo, "rotationY", -360, 360).onChange((v) => {
          console.log('rotationY:', v);
          this.lightLight.transform.rotationY = v;
      });
      lightFolder.add(lightInfo, "rotationZ", -360, 360).onChange((v) => {
          console.log('rotationZ:', v);
          this.lightLight.transform.rotationZ = v;
      });
      lightFolder.addColor(lightInfo, "lightColor").onChange((v) => {
          console.log('lightColor:', v);
          let color: Color = new Color();
          color.setHex(v);
          this.lightLight.lightColor = color;
      });
      

      以上代码运行的效果如下:
      71ddfcd4-9203-4e21-bfed-a8fe640de169-image.png
      可以看到点光源是一个球形的光照效果,一般用来模拟点状的光源,计算量大于平行光源。因为点光源向各个方向的光线强弱相同,所以调整方向不会有效果,但是位置的作用非常明显。
      建议实现这个代码,实际进行操作可以加强印象和理解。

      聚光灯

      聚光灯与点光源非常类似,与点光源相比聚光灯只显示一个椎体范围内的效果,通常用来模拟手动筒,探照灯等这些发光体。
      聚光灯所支持的参数除点光源以外还有以下几个:

      • innerAngle(内切角):光锥内切角,聚光在小于这个角度的范围内有光线
      • outerAngle(外切角):光锥外切角,光线会在内切角到外切角的范围内逐步衰减到0
      • 位置与方向:聚光灯光源受位置和方向双重影响,所以可以通过对应的对象调整位置与方向。
        关键调用示例代码如下:
      // 创建光照,应该已经很熟了吧,不做过多解释
      let sp = new SphereGeometry(0.5, 10, 10);
      
      let lightObj = new Object3D();
      
      let mr = lightObj.addComponent(MeshRenderer);
      mr.geometry = sp;
      mr.material = new HDRLitMaterial();
      
      this.spotLight = lightObj.addComponent(SpotLight);
      this.spotLight.castShadow = true;
      this.scene.addChild(lightObj);
      lightObj.y = 10;
      
      // 增加界面操作
       const lightInfo = {
          intensity:1.0,
          range:0,
          radius:0,
          innerAngle:0,
          outerAngle:0,
          at:0,
          x:0,
          y:0,
          z:0,
          rotationX:0,
          rotationY:0,
          rotationZ:0,
          lightColor:'#fff',
      }
      
      let lightFolder = gui.addFolder("Light");
      lightFolder.add(lightInfo, "intensity", 0, 10).step(0.1).onChange((v) => {
          console.log('intensity:', v);
          this.spotLight.intensity = v;
      });
      lightFolder.add(lightInfo, "range", 0, 100).step(0.1).onChange((v) => {
          console.log('range:', v);
          this.spotLight.range = v;
      });
      lightFolder.add(lightInfo, "radius", 0, 10).step(0.1).onChange((v) => {
          console.log('radius:', v);
          this.spotLight.radius = v;
      });
      lightFolder.add(lightInfo, "at", 0, 10).step(0.1).onChange((v) => {
          console.log('at:', v);
          this.spotLight.at = v;
      });
      lightFolder.add(lightInfo, "innerAngle", 0, 100).step(0.1).onChange((v) => {
          console.log('innerAngle:', v);
          this.spotLight.innerAngle = v;
      });
      lightFolder.add(lightInfo, "outerAngle", 0, 100).step(0.1).onChange((v) => {
          console.log('outerAngle:', v);
          this.spotLight.outerAngle = v;
      });
      lightFolder.add(lightInfo, "x", -10, 10).onChange((v) => {
          console.log('x:', v);
          this.spotLight.transform.x = v;
      });
      lightFolder.add(lightInfo, "y", -10, 10).onChange((v) => {
          console.log('y:', v);
          this.spotLight.transform.y = v;
      });
      lightFolder.add(lightInfo, "z", -10, 10).onChange((v) => {
          console.log('z:', v);
          this.spotLight.transform.z = v;
      });
      lightFolder.add(lightInfo, "rotationX", -360, 360).onChange((v) => {
          console.log('rotationX:', v);
          this.spotLight.transform.rotationX = v;
      });
      lightFolder.add(lightInfo, "rotationY", -360, 360).onChange((v) => {
          console.log('rotationY:', v);
          this.spotLight.transform.rotationY = v;
      });
      lightFolder.add(lightInfo, "rotationZ", -360, 360).onChange((v) => {
          console.log('rotationZ:', v);
          this.spotLight.transform.rotationZ = v;
      });
      lightFolder.addColor(lightInfo, "lightColor").onChange((v) => {
          console.log('lightColor:', v);
          let color: Color = new Color();
          color.setHex(v);
          this.spotLight.lightColor = color;
      });
      

      运行界面效果如下:
      1850f7b0-3fe6-4e40-8e1f-a6ac07dca197-image.png

      可以将聚光灯当成一个手电筒玩耍,多操作界面操作,会很快熟悉这种光源的。

      其它

      orilluson对功能模块进行了重新划分,Stats模块需要单独安装,执行命令 npm install @orillusion/stats --save进行安装,引入代码修改为import { Stats } from "@orillusion/stats";其它不变。

      小结

      这是第一次接触光照的特性,所以从最简单易于理解的三种光源来着手,orilluson提供的这三类光源非常方便,为我接触3D的光照提供了一个很好的切入点。后面要继续熟悉环境光,全局光照,以前阴影等等。
      作为3D新手,后续会不断的记录学习过程,期待与你一起学习一起飞!

      1 条回复 最后回复 回复 引用 1
      • First post
        Last post

      Recent Post

      • 请问有没有本次测试所使用的threejs、babylon和orillusion的源码?

        • 阅读更多
      • B

        哪位大佬知道,纹理闪烁是怎么回事吗?.

        • 阅读更多
      • @StephenChips 同求

        • 阅读更多
      • A

        请问这个入门系列有 demo 代码没有

        • 阅读更多
      • O

        经过几次的学习已经能够构建出一个空间(场景),并在空间中创建物体(几何体),物体可以有不同的外观(材质),与现实的效果足够逼真(光照),终于把最重要的相关性最强的几部分3D功能用起来了。不过面对这块空间想做点什么,又感觉缺少了点什么,是的,只能观看不能操作,如果我要通过键盘、鼠标对场景进行实时的干预该如何做呢,经过了解输入系统可以满足我们的要求。

        输入系统

        输入系统是个比较杂乱的部分,不同平台都有对应的封装,我们可以回忆一下Win32编程将键盘和鼠标的输入集成到了事件系统,用户操作按键或操作鼠标会触发对应的消息码,指示消息,附带参数包含具体的按键信息或鼠标信息,按键信息一般包含按键码或鼠标键位。再回忆一下DOM的事件系统,使用addEventListener将click或mouse类的事件挂载,然后在回调函数中获得结果……
        回忆结束我们可以总结出来几个输入系统的特点:1、挂载感兴趣的事件;2、回调函数得到触发时处理业务逻辑。需要注意的是,键盘需要有按键表进行区分按键,对应的是鼠标需要区分不同按键,以及屏幕坐标,辅助键等一些附属信息。
        出于好奇orilluson的输入系统如何实现的,找来源码进行了一个大体的了解,可以看到输入系统的核心类是InputSystem,该类继承于CEventDispatcher类,CEventDispatcher类是可调度事件的所有类的基类,包含了事件的注册,注销,分发和清理等功能实现。内部保存了监听对象列表,当有消息需要处理时通过遍历监听器列表触发回调函数。InputSystem继承了CEventDispatcher类的事件处理能力外着重实现了键盘鼠标的事件处理。
        具体执行步骤如下:

        Engine3D.init:初始化引擎后,实例化了InputSystem类,并将canvas实例传入InputSystem类; InputSystem.initCanvas:InputSystem监听了画布的键盘与鼠标事件; addEventListener:引擎或对象通过addEventListener函数来挂载用户监听; dispatchEvent:当有挂载的监听事件响应时,回调函数会得执行。
        在输入系统的支持下,可以很轻松的使用键盘和鼠标与触控。
        输入系统的回调事件在类CEvent中,先熟悉一下这个类的常用定义: type:事件类型对应的一个字符串常量; param:注册事件时传递的参数,在注册事件时写入的参数在这里可以读出; ctrlKey:事件发生时 Ctrl 是否被按下,通过查询该键的值来判断Ctrl键的状态; altKey:事件发生时 Alt 是否被按下,通过查询该键的值来判断Alt键的状态; shiftKey:事件发生时 Shift 是否被按下,通过查询该键的值来判断Shift键的状态; 关于坐标

        一直以来的学习路径是以实用为主,但是现在必须要接触一点点不能称之为理论的理论了,那就是坐标系统。

        世界坐标

        首先要解决一个困惑的地方,过去在3D空间中的所有坐标都可以称为世界坐标,世界坐标是三维的,有三个维度(x,y,z),一般在引擎中创建可以由系统使用,开发用户程序需要遵守引擎对于世界的规划,相当于场景作为一个空间,世界坐标是对这个空间制定的规则。这里歪个楼,骇客帝国之所以叫矩阵,是不是因为在3D引擎中对空间世界的处理也是以矩阵为基础的。再拉回来,世界坐标一般以(0,0,0)为中心,我们创建的物体默认的位置也是在这里的,这里是世界的中心,一般分为右手或左手坐标系,好了关于世界坐标系这里已经够用了。

        屏幕坐标

        说回到屏幕坐标是我们过去所熟悉的,首先屏幕坐标是一个二维坐标,以像素为单位,屏幕的左下角为起点,向屏幕的左侧和上方依次是x和y坐标的正向。在网页开发中我们通过DOM事件系统获得的当前坐标一般都是指的屏幕坐标。在网页开发中并不是绝对的没有z轴,CSS中的z-index属性是否可以理解成一种z轴坐标呢。

        相互转换

        屏幕坐标是我们最终渲染到屏的最终展现形式,世界坐标是在三维空间内的标识,两者经常需要相互转换,例如今天需要讨论的输入系统的使用。假设在屏幕上点击了一个位置,需要转换到世界坐标,相似的在世界坐标内的位置或距离也需要转换为屏幕坐标。
        坐标转换有标准的算法,这里我们不必如此费力,完全可以借助引擎的工具,经过一翻查找,在相机组件的实现类Camera3D,有坐标转换的工具,可以一起熟悉一下

        object3DToScreenRay:世界坐标转换屏幕坐标; ScreenRayToObject3D:屏幕坐标转换为世界坐标; 键盘输入

        使用键盘输入,首先需要熟悉两种键盘事件:

        KEY_DOWN:键盘按下事件,使用输入系统挂载该事件,将会得到按下键盘事件通知; KEY_UP:键盘弹起事件,使用输入系统挂载该事件,将会得到弹起键盘事件通知;
        下面来一起梳理一下使用流程: 初始化:必要的引擎初始化; 输入挂载:使用键盘挂载系统指定事件和回调; 处理回调:在回调中获取参数。 基础示例

        这里写了一个最基本的示例,只将键盘的事件打印了出来。

        import { Engine3D, Scene3D, Object3D, Camera3D, HoverCameraController, ForwardRenderJob, DirectLight, KeyEvent } from "@orillusion/core"; export default class Keyboard { cameraObj: Object3D; camera: Camera3D; scene: Scene3D; boxObj: Object3D; async run() { await this.init(); await this.setup(); await this.start(); } /*** * 配置并初始化引擎 */ private async init() { // 初始化引擎 await Engine3D.init(); // 创建一个场景 this.scene = new Scene3D(); // 创建一个相机 this.cameraObj = new Object3D(); this.camera = this.cameraObj.addComponent(Camera3D); // 设置相机类型 this.camera.perspective(60, window.innerWidth / window.innerHeight, 1, 5000.0); // 设置相机控制器 let controller = this.cameraObj.addComponent(HoverCameraController); controller.setCamera(20, -20, 25); // 添加相机至场景 this.scene.addChild(this.cameraObj); } /** * 引擎功能代码 */ private async setup() { Engine3D.inputSystem.addEventListener(KeyEvent.KEY_UP, this.keyUp, this); Engine3D.inputSystem.addEventListener(KeyEvent.KEY_DOWN, this.keyDown, this); } /** * 启动渲染 */ private async start() { // 创建前向渲染 let renderJob: ForwardRenderJob = new ForwardRenderJob(this.scene); // 开始渲染 Engine3D.startRender(renderJob); } private keyDown(e: KeyEvent) { console.log('keyDown:', e.keyCode, e); } private keyUp(e: KeyEvent) { console.log('keyUp:', e.keyCode, e); } }

        运行这个示例后,在场景中按下或弹起键盘,在控制台能够看到输出。

        KeyEvent

        在回调函数中获得的参数类型是KeyEvent,KeyEvent是CEvent的子类,除了CEvent类的参数外,对于键盘事件的使用主要在于对该类型的解析,这里需要详细的了解事件的参数细节,常用到的需要进行一个了解:

        keyCode:按键code值,枚举类型可以参考官方文档的KeyCode定义。 鼠标与触控

        电脑端的鼠标操作与移动端的触控操作有许多共同的地方,在具体用法时如果能够合并为一,是可以节省一半的事件挂载操作的,不过需要留意触控与鼠标的事件对应关系。
        有了前面键盘操作的基础,鼠标与触控使用类型,我们先看支持的事件类型:

        POINTER_CLICK:触摸点击事件,对应鼠标的单击事件; POINTER_MOVE:触摸滑动事件,对应鼠标的移动事件 POINTER_DOWN:触摸开始事件, POINTER_UP:触摸结束事件 POINTER_OUT:触摸滑出事件
        既然已经合并了,后面鼠标与触控用触控来说明吧。 基础示例

        先实现一个最基础的触控功能,与键盘类似,先注册事件,然后响应事件。

        import { Engine3D, Scene3D, Object3D, Camera3D, HoverCameraController, ForwardRenderJob, PointerEvent3D } from "@orillusion/core"; export default class Mouse { cameraObj: Object3D; camera: Camera3D; scene: Scene3D; async run() { await this.init(); await this.setup(); await this.start(); } /*** * 配置并初始化引擎 */ private async init() { // 初始化引擎 await Engine3D.init(); // 创建一个场景 this.scene = new Scene3D(); // 创建一个相机 this.cameraObj = new Object3D(); this.camera = this.cameraObj.addComponent(Camera3D); // 设置相机类型 this.camera.perspective(60, window.innerWidth / window.innerHeight, 1, 5000.0); // 设置相机控制器 let controller = this.cameraObj.addComponent(HoverCameraController); controller.setCamera(20, -20, 25); // 添加相机至场景 this.scene.addChild(this.cameraObj); } /** * 引擎功能代码 */ private async setup() { Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onUp, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onDown, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_CLICK, this.onPick, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_OVER, this.onOver, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_OUT, this.onOut, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onMove, this); } /** * 启动渲染 */ private async start() { // 创建前向渲染 let renderJob: ForwardRenderJob = new ForwardRenderJob(this.scene); // 开始渲染 Engine3D.startRender(renderJob); } private onUp(e: PointerEvent3D) { console.log('onUp:',e); } private onDown(e: PointerEvent3D) { console.log('onDown:',e); } private onPick(e: PointerEvent3D) { console.log('onPick:',e); } private onOver(e: PointerEvent3D) { console.log('onOver:',e); } private onOut(e: PointerEvent3D) { console.log('onOut:',e); } private onMove(e: PointerEvent3D) { console.log('onMove:',e); } } PointerEvent3D

        触控的参数是以PointerEvent3D类型作为回调函数的参数传递到应用,PointerEvent3D是CEvent的子类,除了CEvent类的参数外,需要熟悉一下这个类型的关键字段。

        mouseX:当前鼠标所在位置的X坐标; mouseY:当前鼠标所在位置的Y坐标; movementX:当前事件和上一个鼠标事件之间鼠标在水平方向上的移动值; movementY:当前事件和上一个鼠标事件之间鼠标在垂直方向上的移动值;
        坐标系列的数值请注意,可以使用前面相机组件提供的转换函数进行转换,不必自己写算法进行转换。 由对象挂载

        前面的挂载直接由引擎的输入系统挂载,这样在整个场景中都会响应,如果只需要在一个物体中响应鼠标的事件,我们可以将事件挂在物体上,为什么可以这么做呢,找出来代码可以看到,物体的容器是Object3D类,而Object3D类是Entiry的子类,Entity的父类是CEventDispatcher类,正是因为Object3D通过CEventDispatcher,继承了事件的能力。这一套继承加组件式的结构,实在是太好用了,有没有。
        这样就有了以下的代码:

        // 创建一个对象 this.boxObj = new Object3D(); this.boxObj.localPosition = new Vector3(0,0,0); // 创建渲染组件 let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer); // 设置形状 mr.geometry = new BoxGeometry(5, 5, 5); // 设置材质 mr.material = new HDRLitMaterial(); // 添加到场景 this.scene.addChild(this.boxObj); boxObj.addEventListener(PointerEvent3D.PICK_CLICK, this.onClick, this); onClick(e: PointerEvent3D) { console.log('onPick:',e); }

        运行后可以在控制台看到输出

        小结

        经过前面几次的学习,已经能够完事的构建出一个空间了,但是这块空间仍然缺乏灵动的能力,不能随时响应我们的操控,输入系统是一个随时干预系统的大杀器,可以让我们获得掌控感,是否控制欲获得了满足。
        今天只是一些最基础的用法,发挥想象力可以使这个空间好玩起来了。
        作为3D新手,后续会不断的记录学习过程,期待与你一起学习一起飞!

        • 阅读更多

      Copyright © 2022 Orillusion | Contact US