Orillusion

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

    orillusion入门系列三 | 几何体

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

      前两次的学习总结中,成功运行了一个最基础的功能,对引擎的的整体代码进行了归纳,根据我的习惯提供了一个并不严谨的开发步骤,并且介绍了两个工具。主要解决了认识引擎以及如何开始使用引擎。今天我准备学习使用引擎开发真正的功能了,在这里继续使用大白话(水平有限只能如此)介绍学习过程。
      专业的3D系统开发需要符合软件工程实践,只以像我这样的小白视角以入门为目的提供一个思路,我们前面了解到首先要通过场景开辟一个空间,加上相机开启上帝视角,那么之后呢?我认为是“造物”,一个3D空间无论复杂还是简单,都可以看成是一个虚拟世界,是对真实世界的理解的反映,在真实世界中我们能看到的物体是由点、线、面组成的,在3D场景中最基础的是由点组成的,3D中的点由三个坐标(x、y、z)分量构成的,GPU在处理时一般是按照三角型处理的,这些点我们一般称为顶点。在3D中的一座山、一条路、一个篮球,都是由若干的顶点构成的。但是只有顶点是不够的,每个物体还会有不同的外观,我们一般用材质来表示,材质对物体的外观进行装饰成不同的样式。所以顶点+材质就组成了一个物体,这个物体我们一般称为网格(mesh),今天我们先忽略材质,专注于造物。

      几何体

      面向3D的世界我还是学前班阶段,所以我们从最基础的几何体开始。orillusion目前提供了四种几何体可以直接使用,并不算多,实践中肯定会需要更多的类型吧,期待后续会增加,这里先熟悉这四种,对于了解几何体是足够的了。

      长方体

      长方体是我的最爱,我们在第一天就熟悉了如何使用长方体,一个长方体由宽度、高度、深度三个分量组成,这里我们复习一下如何使用

      // 创建一个容器对象
      this.boxObj = new Object3D();
      // 创建渲染组件
      let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer);
      // 创建一个长方体
      mr.geometry = new BoxGeometry(5, 5, 5);
      // 设置材质
      mr.material = new HDRLitMaterial();
      // 添加到场景
      this.scene.addChild(this.boxObj);
      

      99816cf9-e104-441d-aaba-f88ab72545b9-image.png
      这里需要注意,几何体的属性在创建时通过构造函数参数指定,不支持动态的修改,动态改变形状建议使用Object3D对象的缩放属性。

      球体

      球体也是我们非常熟悉的一种几何体,创建球体必须要指定半径,以及水平和垂直分段数。

      // 创建一个对象
      this.boxObj = new Object3D();
      // 创建渲染组件
      let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer);
      // 设置球体的实例
      mr.geometry = new SphereGeometry(3, 100, 100);
      // 设置材质
      mr.material = new HDRLitMaterial();
      // 添加到场景
      this.scene.addChild(this.boxObj);
      

      运行效果如下
      a3cd9adc-1d7f-4789-9e22-1081a398f3f0-image.png

      平面

      创建一个平台我们至少需要指定长和宽两个属性

      // 创建一个对象
      this.boxObj = new Object3D();
      // 创建渲染组件
      let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer);
      // 设置形状
      mr.geometry = new PlaneGeometry(10, 10);
      // 设置材质
      mr.material = new HDRLitMaterial();
      // 添加到场景
      this.scene.addChild(this.boxObj);
      

      运行效果如下
      512a8267-23ee-4f83-b539-0e4c71d95128-image.png

      圆柱体

      我们这里创建一个半径为5,高为10的圆柱体

      // 创建一个对象
      this.boxObj = new Object3D();
      // 创建渲染组件
      let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer);
      // 设置形状
      mr.geometry = new CylinderGeometry(5, 5, 10);
      // 设置材质
      mr.material = new HDRLitMaterial();
      // 添加到场景
      this.scene.addChild(this.boxObj);
      

      运行效果如下
      99c32a9a-92a1-4819-84a9-a8e30506b1b0-image.png

      Object3D 对象

      我们不是第一次接触Object3D对象了,这里我们通过实例用一下这个组件,我们以长方体为例,长方体是通过组件的方式添加到一个Object3D容器中的,所以通过Object3D可以操作立方体的属性。

      位置

      分别可以直接读写对象的x、y、z坐标。

      this.boxObj.x = v;
      this.boxObj.y = v;
      this.boxObj.z = v;
      

      也可以通过 Vector3 类型一次性设置三个分量,这里不作演示了

      旋转

      分别可以直接读写对象x、y、z三个方向的旋转角度。

      this.boxObj.rotationX = v;
      this.boxObj.rotationy = v;
      this.boxObj.rotationz = v;
      

      也可以通过 Vector3 类型一次性设置三个分量,这里不作演示了

      缩放

      分别可以直接读写对象x、y、z三个方向的缩放。

      this.boxObj.scaleX = v;
      this.boxObj.scaleY = v;
      this.boxObj.scaleZ = v;
      

      也可以通过 Vector3 类型一次性设置三个分量,这里不作演示了

      动态演示或隐藏

      设置对象的 visible 属性可以对对象演示或隐藏

      this.boxObj.visible = v;
      

      使用脚本

      前面创建的物体看起来很死板,用鼠标操作一下才会动,如何让这个自己有一定的行为呢。那要请出组件了。组件一般用来封装可复用的功能,添加至不同的Object3D中,引擎内部会自动调用该组件的功能作用在这个容器对象中。
      这里我们看一个最基本的组件脚本的模板:

      class Script extends ComponentBase {
        // 覆写 初始化
        public init(){
          // 该函数在组件被创建时调用,可以用来初始化内部的变量
          // 注意,此时组件被挂载到 Object3D 上,所以无法访问 this.object3D
        }
        // 覆写 渲染开始
        public start(){
          // 该函数在组件开始渲染前被调用,
          // 一颗访问 this.object3D, 通常用来获取节点的属性或其他组件
        }
        // 覆写 update
        public update() {
          // 每帧渲染循环调用,通常定义节点的循环逻辑
          // 例如,每一帧更新物体旋转角度
          this.object3D.rotationY += 1;
        }
      }
      

      以上模板的注释说明了用法,这里我准备做一个自动旋转的功能,只要实现 update 函数就可以做到。

      update(): void {
        // 旋转
        this.transform.rotationX = Math.sin(Time.time * 0.001) * 100.0;
      }
      

      之后将该组件添加至boxObj中,看来需要熟识上面的脚本模板,这几个生命周期函数非常重要,在后面定制功能时必不可少。而且除了用户代码,引擎内部也定义了一些组件,后面我们要不断去了解。

      完成代码

      这里以立方体为例,将代码罗列一下。

      import { Engine3D, Scene3D, Object3D, Camera3D, HoverCameraController, MeshRenderer, BoxGeometry, HDRLitMaterial, ForwardRenderJob, Stats } from "@orillusion/core";
      import * as dat from 'dat.gui';
      import { RotationScript } from "./rotationScript";
      
      export default class Geometry {
      
          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();
          }
      
          /**
           * 引擎功能代码
           */
          private async setup() {
              // 创建一个场景
              this.scene = new Scene3D();
      
              // 添加性能监控面板
              this.scene.addComponent(Stats);
              // 创建一个相机
              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);
      
              this.createBox();
      
              this.addGUI();
      
          }
      
          /**
           * 启动渲染
           */
          private async start() {
              // 创建前向渲染
              let renderJob: ForwardRenderJob = new ForwardRenderJob(this.scene);
              // 开始渲染
              Engine3D.startRender(renderJob);
          }
      
          /**
           * 创建立方体
           */
          private async createBox() {
              // 创建一个对象
              this.boxObj = new Object3D();
              // 挂载脚本
              this.boxObj.addComponent(RotationScript);
              // 创建渲染组件
              let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer);
              // 设置形状
              mr.geometry = new BoxGeometry(5, 5, 5);
              // 设置材质
              mr.material = new HDRLitMaterial();
              // 添加到场景
              this.scene.addChild(this.boxObj);
      
          }
      
          private async addGUI(){
              // 创建 dat 实例
              const gui = new dat.GUI();
              // 创建保存属性值对象
              const geometryInfo = {
                  enable:true,
                  visible:true,
                  rotationX:0,
                  rotationY:0,
                  rotationZ:0,
                  scaleX:0,
                  scaleY:0,
                  scaleZ:9,
                  x: 0,
                  y: 0,
                  z: 0,
              };
      
              // 创建一个x坐标事件监听,当修改x值时,直接修改立方体坐标。
              gui.add(geometryInfo, "enable").onChange((v) => {
                  console.log('enable:', v);
                  this.boxObj.enable = v;
              });
              gui.add(geometryInfo, "visible").onChange((v) => {
                  console.log('visible:', v);
                  this.boxObj.visible = v;
              });
              gui.add(geometryInfo, "x", -100, 100).step(0.1).onChange((v) => {
                  console.log('x:', v);
                  this.boxObj.x = v;
              });
              gui.add(geometryInfo, "y", -100, 100).step(0.1).onChange((v) => {
                  console.log('y:', v);
                  this.boxObj.y = v;
              });
              gui.add(geometryInfo, "z", -100, 100).step(0.1).onChange((v) => {
                  console.log('z:', v);
                  this.boxObj.z = v;
              });
              gui.add(geometryInfo, "rotationX", -100, 100).step(0.1).onChange((v) => {
                  console.log('rotationX:', v);
                  this.boxObj.rotationX = v;
              });
              gui.add(geometryInfo, "rotationY", -100, 100).step(0.1).onChange((v) => {
                  console.log('rotationY:', v);
                  this.boxObj.rotationY = v;
              });
              gui.add(geometryInfo, "rotationZ", -100, 100).step(0.1).onChange((v) => {
                  console.log('rotationZ:', v);
                  this.boxObj.rotationZ = v;
              });
      
              gui.add(geometryInfo, "scaleX", 0, 10).step(0.1).onChange((v) => {
                  console.log('scaleX:', v);
                  this.boxObj.scaleX = v;
              });
              gui.add(geometryInfo, "scaleY", 0, 10).step(0.1).onChange((v) => {
                  console.log('scaleY:', v);
                  this.boxObj.scaleY = v;
              });
              gui.add(geometryInfo, "scaleZ", 0, 10).step(0.1).onChange((v) => {
                  console.log('scaleZ:', v);
                  this.boxObj.scaleZ = v;
              });
          }
      
      }
      
      

      脚本完整代码

      import { ComponentBase, Time } from "@orillusion/core";
      
      export class RotationScript extends ComponentBase {
      
          update(): void {
            // 旋转
            this.transform.rotationX = Math.sin(Time.time * 0.001) * 100.0;
          }
        }
        
      

      668c248c-7592-4935-8ed4-76b70e37e3b9-image.png

      因为加上了脚本,运行时能够看到这个方立体在自动旋转。右侧的操作面板做对应的操作也可以看到变化。

      小结

      今天学习了最基本的功能,没有按照通常的3D学习顺序,这里只按照最朴素(土)的习惯性思维来介绍。现在我们学会了造物,后续要继续学习如何装扮这些物体。
      看到了社区的反馈,有大佬对使用vue框架持提出质疑,瑟瑟发抖中,后面略去界面库部分。
      作为3D新手,后续会不断的记录学习过程,期待与你一起学习一起飞!

      支阿怪 1 条回复 最后回复 回复 引用 2
      • 支阿怪
        支阿怪 @oldguy 最后由 编辑

        @oldguy 请问orillusion引擎库是怎么安装的呢?npm install @orillusion/core --save这个步骤一直安装失败。

        6ddfcd50-8210-47f0-bd10-5519090cf29d-image.png

        没有捷径,自发光芒

        shuangliu 1 条回复 最后回复 回复 引用 0
        • shuangliu
          shuangliu @支阿怪 最后由 编辑

          @支阿怪 目前引擎库还没有公开,所以无法直接安装,我们正在做内测,稍后会进行公开测试

          1 条回复 最后回复 回复 引用 0
          • 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