• 版块
  • 最新
  • 标签
皮肤
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(不使用皮肤)
  • 不使用皮肤
折叠

Orillusion

0

在线

525

用户

151

主题

408

帖子

orillusion入门系列二 | 快速入门

已定时 已固定 已锁定 已移动 中文社区
orillusion引擎engine
5 帖子 4 发布者 948 浏览
    • 从旧到新
    • 从新到旧
    • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • O 离线
    O 离线
    oldguy
    写于 最后由 oldguy 编辑
    #1

    前文我们自己动手使用引擎体验到了3D的效果,今天我们尝试梳理一下使用引擎做3D开发从何处入手,快速的从整体上了解如何使用 orillusion 开发3D项目。

    引擎的挑战

    3D是一项面向视觉的技术,为了获得更逼真、更炫酷、更流畅的体验,需要极强的理论根基和工程实践经验。建议先粗略的看看引擎所要面对的一些实际问题,了解一下对引擎浮浅的认识,以便我们能更好的理解如何使用引擎。

    • 从贵族到平民 数学是构建3D世界的支柱,3D效果的发展离不开对数学和算法的深刻理解和应用,比如为了体现光线的真实感,为了实现服装飘逸的感觉,都有许多个数学公式作为底层支撑。另一方面需要充分了解硬件的特性,这都是非常耗费时间的工作,引擎使得没有这方面基础的普通开发者可以集中时间在实现需求上。
    • 从贪婪到克制 无论硬件是否会继续以遵循摩尔定律的规律提升,引擎要以足够贪婪的程度榨取硬件的性能,使硬件上的投资获得回报,同时要克制自身对资源的占用,即要又要的典范。
    • 从混乱到秩序 引擎所面向的世界是多方面的,不同的硬件之间如何协调,多变的网络环境,多种资源处理,稳定灵活高效的任务调度等等,在引擎的帮助下有条不紊的组织在一起。
    • 始终面带微笑 引擎要发挥出足够的作用,必须要让用户足够容易上手,提供给用户要有足够友好的api,还有完备的工具链和文档,所以引擎要提供尽可能的友好使用体验。

    使用引擎

    因为以上罗列的一些原因,引擎需要做许多取舍,在使用引擎的时候也有一些固定的要求。大体上我们分为搭建环境、引擎配置、引擎初始化、开启渲染任务这几个步骤。

    搭建环境

    Orillusion 支持多种方式安装,具体可以参考官方文档,上一篇文章使用了 cdn引用和 vue&vite 系列的开发环境,这里假设您已经进行了安装。

    引擎配置

    引擎为了满足多样的需求和不同的环境,提供了许多配置选项,在代码的最初位置进行引擎配置,后续的初始化和运行需要依赖配置项。这里只列出两条配置示例,更多的配置项可以参考官方文档。

    // 最大实体数量
    Engine3D.setting.memory.doMatrixMaxCount = 100000;
    // 最大灯光数量
    Engine3D.setting.light.maxLight = 1024;
    

    初始化

    引擎进行了配置之后,需要进行初始化,在初始化这一步可以根据需求申请必要的内存。这里我们可以配置 canvas变量,也可以指定渲染前回调、每一帧回调以前每一帧渲染后的回调。

    // 先配置,后初始化
    await Engine3D.init({
        canvasConfig:{
            // 配置 cavans
            canvas: document.getElementById("webGpuCanvas"),
            alpha: false,
            zIndex: 1
        },
        beforeRender: ()=>{
            // 每一帧渲染前回调
        },
        renderLoop: ()=>{
            // 每一帧回调
        },
        lateRender: ()=>{
            // 每一帧渲染后回调
        }
    });
    

    我们目前没有特别的功能需求,一般用最简化的初始化代码。

    await Engine3D.init();
    

    功能代码

    编写一个相对简单的3D程序,我们可以简单的将过程理解为几个步骤:

    1. 开辟一个3D空间:创建一个场景,相当于一个3D空间,后续的资源可以添加到这个场景中。
    // 创建一个场景
    let scene3D: Scene3D = new Scene3D();
    
    1. 设置一个观察点:这个观察点我们一般用相机组件来体现,所有看到的场景内的信息都是通过相机组件的角度实现的,相机支持一系列的配置参数和方法,后续我们会有专门的章节来学习,同时该相机也要添加至场景中。
    // 创建一个实体对象,用来管理相机组件
    let cameraObj: Object3D = new Object3D();
    // 向 相机 对象内添加相机组件 Camera3D 是我们的相机组件
    let camera = cameraObj.addComponent(Camera3D);
    
    // 相机的配置略
    ...
    
    // 添加相机至场景
    scene3D.addChild(cameraObj);
    
    1. 添加物体:这里我们为了演示,添加了一个立方体,同样需要添加至场景中。
    // 创建一个对象
    const obj = new Object3D();
    // 创建渲染组件
    let mr = obj.addComponent(MeshRenderer);
    // 创建一个几何体,这里是box
    mr.geometry = new BoxGeometry(5, 5, 5);
    // 设置材质
    mr.material = new LitMaterial();
    // 添加到场景
    scene3D.addChild(obj);
    

    开始渲染任务

    所谓渲染形象来说是,将场景内的景物,通过相机作为观察点,生成二维图像,显示在演示设备上的过程。我们这里一般显示设备是前端的canvas,所以渲染可以理解为从场景到canvas的过程,为了保持流畅,需要高速的刷动作。
    渲染任务是通过3D视图将场景与相机组织到一起,提供给引擎进行渲染。

    // 创建View3D对象
    let view = new View3D();
    // 指定渲染的场景
    view.scene = scene3D;
    // 指定使用的相机
    view.camera = camera;
    // 开始渲染
    Engine3D.startRenderView(view);
    

    后处理

    从代码上看,后处理是要放到开始渲染任务之前,但是从逻辑上这里放到最后一步,因为后处理是在生成图片后,界面显示前所做的一次纯粹的图片处理。
    得益于组件化的架构设计,尽管后处理的类型比较多,但是可以使用统一的组件系统,后续会非常熟悉组件系统的用法,暂时可以有个印象即可。

    ...
    
    // 创建一个后处理组件
    let postProcessing = this.scene.addComponent(PostProcessingComponent);
    // 向后处理组件中添加效果,有这么多内置效果,可以用同样的方式添加
    postProcessing.addPost(DepthOfFieldPost); //景深效果。
    
    ...
    

    后处理是个相对独立又非常有趣的功能,后续我们会专门深入了解。

    调测工具

    为了更好的观察程序的运行状态和动态的操控功能,了解两款相对应的工具很有必要。

    性能监控(Stats)

    Orillusion 官方提供的一个性能监控工具组件 Stats,可以显示引擎的运行状态,我们可能直接添加到场景中即可,默认会显示在运行界面的左上角,显示位置可以修改,这里我们使用默认设置就可以了。Stats 不在引擎的核心包中,需要从扩展包中安装:npm install @orillusion/stats --save ,安装后按照以下代码使用

    import { Stats } from "@orillusion/stats"
    scene.addComponent(Stats);
    

    界面操控(dat.gui)

    一段程序在完成时,逻辑已经通过代码固定下来了,若需动态的改变程序逻辑,脱离不开设计好的输入控制和代码本身的逻辑。但是出于调试或测试的原因,需要动态的修改某个api或变量,我们假设只通过界面来控制逻辑,orillusion 官方提供了 GUIHelp 工具类来实现这个功能,不过我们当前推荐使用 dat.gui 来做界面操控工具。

    简介

    dat.gui 是由google工程师出品的很轻量级界面操控工具,使用 javascript 实现,可以方便的集成至基于web的系统内,实现灵活的界面操控,特别适合作为3D程序观察调试程序的工具。
    dat.gui的优点显而易见:

    • 使用简单 dat.gui可以自动的操作dom节点,同步至界面显示效果,不需要我们手动繁琐的通过js来操作dom结构。
    • 轻量级 dat.gui代码量不大,不会对系统的加载造成太大的负担。
    • 功能强大 dat.gui提供了数字、逻辑、颜色、字符串、函数等几种数据类型,不同的数据类型有与之相适配的界面元素,为修改代码的变量和逻辑提供了很大的便利。

    用法

    详细的dat.gui建议查看官方或其它资料,我们这里只是简单的介绍需要用到的部分,后续随着操控部分的增加也会不断的更新,现在我们仅需要熟悉事件监听即可。
    目前支持两种事件监听类型:

    事件 触发
    onChange 值被修改时触发
    onFinishChange 失去焦点时触发

    具体代码在后续代码中一共演示,这里以vue&vite环境为例

    编写代码

    1. 添加@别名 以便代码中可以使用 @ 指代源码路径
      a. 安装node类型 npm i @types/node
      b. 修改 vite.config.ts 文件,新加 @ 别名配置
    export default defineConfig({
      resolve: {
        alias: {
          '@': join(__dirname, "src"),
        }
      },
      plugins: [vue()]
    })
    

    c. 修改 tsconfig.json 文件,配置TypeScript类型提示,增加 baseUrl和paths配置项

    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
    
    1. 重构目录结构
      a. 修改 demo 目录为 orilluson
      b. 在 src目录创建 views目录
      c. 在views 目录创建 Index.vue单文件组件,编辑代码如下
    <template>
    
    </template>
    
    <script lang="ts" setup>
      import { onMounted } from 'vue';
      import Hello from '@/orillusion/hello';
      onMounted(()=>{
        new Hello().run();
      })
    </script>
    
    <style scoped>
    </style>
    

    d. 重构项目根目录的App.vue文件,编辑代码如下

    <template>
      <Index></Index>
    </template>
    
    <script lang="ts" setup>
    import Index from "@/views/Index.vue";
    </script>
    
    <style scoped>
    
    </style>
    
    1. 安装 dat.gui: npm install --save dat.gui
    2. 完善 hello.ts ,主要从以下几个方面来进行
      a. 重构 Hello 类,将 函数内的临时变量声明成类成员变量
      b. 根据我们前面的引擎步骤,增加处理函数
      c. 增加 dat.gui 操作立方体的控制项
    3. 完成 hello.ts 代码
    import { Engine3D, Scene3D, Object3D, Camera3D, HoverCameraController, MeshRenderer, BoxGeometry, LitMaterial, View3D, AtmosphericComponent } from "@orillusion/core";
    import {  Stats } from "@orillusion/stats";
    import * as dat from 'dat.gui';
    
    export default class Hello {
    
        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(AtmosphericComponent);
            
            // 添加性能监控面板
            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 view = new View3D();
            // 指定渲染的场景
            view.scene = this.scene;
            // 指定使用的相机
            view.camera = this.camera;
            // 开始渲染
            Engine3D.startRenderView(view);
        }
    
        /**
         * 创建立方体
         */
        private async createBox() {
            // 创建一个对象
            this.boxObj = new Object3D();
            // 创建渲染组件
            let mr: MeshRenderer = this.boxObj.addComponent(MeshRenderer);
            // 设置形状
            mr.geometry = new BoxGeometry(5, 5, 5);
            // 设置材质
            mr.material = new LitMaterial();
            // 添加到场景
            this.scene.addChild(this.boxObj);
        }
    
        private async addGUI(){
            // 创建 dat 实例
            const gui = new dat.GUI();
            // 创建保存属性值对象
            const geometryInfo = {
                x: 0,
                y: 0,
                z: 0
            };
    
            // 创建一个x坐标事件监听,当修改x值时,直接修改立方体坐标。
            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;
            });
        }
    
    }
    
    

    完成项目

    今天的代码我们主要演示了两款测试工具,在左上角是性能监控面板,在右上角是操控面板,用鼠标滑动滚动条或者直接输入数值,可以分别理性立方体的x、y、z的值,物体对应的会发生移动。
    8414362f-b932-4fa1-97d3-fd5cff4010b2-image.png
    可以看到这一个示例比上一节的有了背景环境效果,因为我们向场景中添加了AtmosphericComponent天空盒组件,所以可以看到天空盒效果。

    代码解析

    今天的代码在第一篇的基础上有所增加,但是以下三个类型已经第二次出现了,我们不去深究更详细的原理,需要对这三个常用的对象类型有所了解。

    • Object3D 是引擎内置的实体对象,通常被当做基本的组件容器,可以通过不同组件组合来实现不同的类型功能。我的理解是,Object3D内置一些基础功能对象,还可以是功能组件的容器,比如我们这里创建一个用于管理立方体的容器boxObj。
    • MeshRenderer 是一个用于渲染网格的组件,这个组件非常重要,包含几何属性和材质属性,每个需要渲染的物体都需要有几何属性和材质属性。
    • LitMaterial Light材质,基于物理渲染,旨在模拟现实世界光照效果,以后我们会专门来学习材质的部分,这里只要知道这是一种材质就可以。
      以上三个类型都非常重要,首先我们要创建一个Object3D作为容器,然后在这个容器中创建MeshRenderer作为渲染组件,渲染组件中需要实例化几何体和材质。就这样由容器与功能组件相互配合完成功能,当然都需要按照一定的层级结构添加至场景中。

    小结

    今天根据我的理解总结了一个引擎所必须面对的几个难点,可以更好的理解引擎的设计,同时拆解了 orilluson 代码的几个步骤,以便能够快速的上手3D代码开发。进一步的介绍了两个非常常用的调测工具,为以后自由的调用功能提供了工具。之后继续完善项目,运行项目演示效果。最后我们熟悉了最常见的三个组件。
    作为3D新手,后续会不断的记录学习过程,期待与你一起学习一起飞!

    1 条回复 最后回复
    1
  • A 离线
    A 离线
    ashton
    写于 最后由 编辑
    #2

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

    webGPU

    1 条回复 最后回复
    0
  • 猪 离线
    猪 离线
    猪子
    写于 最后由 编辑
    #3

    我在学习的过程中遇到两个小问题提示一下:
    1.文章中说的修改 tsconfig.ts文件,我没有找到,我是在tsconfig.json文件中修改的。并且要增加的内容放在“compilerOptions”对象里。
    2.hello.ts文件按照文章写完后,最上面的四个属性报错,提示没有初始化,可以在变量名后面加!解决。
    244ea15c-f7b9-4646-b53c-c9cc7cb70fd3-image.png

    O 1 条回复 最后回复
    0
  • O 离线
    O 离线
    oldguy
    在 中回复了 猪子 最后由 编辑
    #4

    @猪子 多谢反馈,已更新

    1 条回复 最后回复
    0
  • T 离线
    T 离线
    Temurayl
    写于 最后由 编辑
    #5

    在页面中改变视角时 如何在控制台查看相机的位置?

    1 条回复 最后回复
    0

Copyright © 2023 Orillusion | Contact US

  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。