DS-SDK封装ThreeJS的三维场景核心库Viewer

目录
  • 正文
    • 一、ThreeJS-ES6库引入
    • 二、初始化渲染器
    • 三、初始化相机
    • 四、初始化场景
    • 五、初始化鼠标控制器
    • 六、灯光初始化
    • 七、全局渲染的函数-逐帧获取页面大小
    • 八、全局动画函数
    • 九、销毁页面

正文

viewer核心库的封装主要是针对threejs场景进行初始封装,以便多项目复用。具体细节我就不多写了,网上一大堆,但是我发现网上的例子都比较雷同,所以我的这一篇文档会着重从我做过的项目上遇到的一些问题来具体描写,详细请看第七、第八小节,主要是第一我们真实项目中,其实你的渲染页面不是整个页面,而且其中的一小块div,所以你的宽高是div而不是windws的(如下图);第二对于页面大小变化的监视,以我的知识结构来说,还没有很好的解决方案来监视div的大小变化。

基础封装初始化包括以下:

一、ThreeJS-ES6库引入

引入部分除了ThreeJS核心库的东西外,还有标签渲染器,用于后期在场景中添加标签,还有控制器何和帧率显示器。

import {
  Cache,
  WebGLRenderer,
  ACESFilmicToneMapping,
  PCFSoftShadowMap,
  sRGBEncoding,
  PerspectiveCamera,
  Scene,
  Color
} from 'three'
// 二维标签渲染器
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import Stats from 'three/examples/jsm/libs/stats.module.js'

二、初始化渲染器

初始化渲染器部分主要是获取渲染画布的dom,然后初始化场景渲染器,初始化二维标签渲染器,和三维标签渲染器。 这一部分代码我们设置渲染器的大小,这个放到了后面会讲。

_initRenderer () {
    // 获取画布dom
    this.viewerDom = document.getElementById(this.id)
    // 初始化渲染器
    this.renderer = new WebGLRenderer({
      logarithmicDepthBuffer: true,
      antialias: true, // true/false表示是否开启反锯齿
      alpha: true, // true/false 表示是否可以设置背景色透明
      precision: 'highp', // highp/mediump/lowp 表示着色精度选择
      premultipliedAlpha: true, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率)
      preserveDrawingBuffer: true // true/false 表示是否保存绘图缓冲
    })
    this.renderer.domElement.style.zIndex = 1
    // 默认情况下,js的光强数值不真实。为了使得光强更趋于真实值,应该把渲染器的physicallyCorrectLights属性设为true
    this.renderer.physicallyCorrectLights = true
    // 尽管我们的贴图不是HDR,但使用tone mapping可以塑造更真实的效果。
    this.renderer.toneMapping = ACESFilmicToneMapping
    // 场景中的阴影自动更新
    this.renderer.shadowMap.enabled = true
    // 设置渲染器开启阴影贴图,并将类型设为PCFSoftShadowMap
    this.renderer.shadowMap.type = PCFSoftShadowMap
    // 这下我们可以看到更亮的材质,同时这也影响到环境贴图。
    this.renderer.outputEncoding = sRGBEncoding
    // 一个canvas,渲染器在其上绘制输出。
    this.viewerDom.appendChild(this.renderer.domElement)
    // 网页标签
    this.labelRenderer = new CSS2DRenderer()
    this.labelRenderer.domElement.style.zIndex = 2
    this.labelRenderer.domElement.style.position = 'absolute'
    this.labelRenderer.domElement.style.top = '0px'
    this.labelRenderer.domElement.style.left = '0px'
    // 避免HTML标签遮挡三维场景的鼠标事件
    this.labelRenderer.domElement.style.pointerEvents = 'none'
    this.viewerDom.appendChild(this.labelRenderer.domElement)
    // 三维标签
    this.css3DRenderer = new CSS3DRenderer()
    this.css3DRenderer.domElement.style.zIndex = 0
    this.css3DRenderer.domElement.style.position = 'absolute'
    this.css3DRenderer.domElement.style.top = '0px'
    this.css3DRenderer.domElement.style.left = '0px'
    // 避免HTML标签遮挡三维场景的鼠标事件
    this.css3DRenderer.domElement.style.pointerEvents = 'none'
    this.viewerDom.appendChild(this.css3DRenderer.domElement)
  }

三、初始化相机

相机参数里面的aspect(摄像机视锥体长宽比),其实应该是画布dom的长宽比,而不是我们浏览器windows的长宽比,请你仔细品品这句话。

参数 构造器 PerspectiveCamera( fov : Number, aspect : Number, near : Number,> far : Number ) fov — 摄像机视锥体垂直视野角度 aspect — 摄像机视锥体长宽比 near — 摄像机视锥体近端面 far — 摄像机视锥体远端面

  _initCamera () {
    // 渲染相机
    this.camera = new PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 5000)
    this.camera.position.set(50, 0, 50)
    this.camera.lookAt(0, 0, 0)
  }

四、初始化场景

  _initScene () {
    // 渲染场景
    this.scene = new Scene()
    this.scene.background = new Color('rgb(5,24,38)')
  }

五、初始化鼠标控制器

控制器主要是用来控制通过鼠标漫游场景的。

参数 OrbitControls(object:Camera,domElement:HTMLDOMElement) object:(必需)要控制的摄像机。相机不得是其他对象的子对象,除非该对象是场景本身。 domElement:用于事件侦听器的HTML元素。

  _initControl (option) {
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    this.controls.enableDamping = false
    this.controls.maxPolarAngle = Math.PI * 0.46// 垂直轨道多远 上限
    this.controls.minPolarAngle = Math.PI * 0.3// 你可以垂直轨道多远,下限
    this.controls.screenSpacePanning = false // 定义平移时如何平移相机的位置 控制不上下移动
  }

六、灯光初始化

没有灯光的话,就会一片漆黑,所以需要添加灯光。

  // 全局光不需要
  const ambientLight = new DS.THREE.AmbientLight(0xffffff, 0.2)
  viewer.scene.add(ambientLight)

七、全局渲染的函数-逐帧获取页面大小

这里是全局渲染的函数,通过requestAnimationFrame函数,可以逐帧去渲染场景。 摄像机视锥体的长宽比,设置渲染器的长宽比,都是这里一直去获取传入的div,而不是window的大小,设置参数(虽然这样写会很耗费性能,但是我也没有找到更好的方法去监听页面的大小变化)。

  function animate () {
      requestAnimationFrame(animate)
      that._undateDom()
      that._readerDom()
      // 全局的公共动画函数,添加函数可同步执行
      that.animateEventList.forEach(event => {
        event.fun && event.content && event.fun(event.content)
      })
    }
    animate()
  // 更新dom大小
  _undateDom () {
    const that = this
    that.controls.update()
    // 摄像机视锥体的长宽比,通常是使用画布的宽/画布的高,所以这里的画布指的是dom,就是一个div,而不是window
    that.camera.aspect = that.viewerDom.clientWidth / that.viewerDom.clientHeight
    // 更新摄像机投影矩阵。在任何参数被改变以后必须被调用,来使得这些改变生效
    that.camera.updateProjectionMatrix()
    //设置渲染器的长宽比,所以就不需要在代码里面去写window的页面监听,来改变页面大小【】
    that.renderer.setSize(that.viewerDom.clientWidth, that.viewerDom.clientHeight)
    //that.renderer.setPixelRatio(window.devicePixelRatio) // 设置设备像素比
    that.labelRenderer.setSize(that.viewerDom.clientWidth, that.viewerDom.clientHeight)
    that.css3DRenderer.setSize(that.viewerDom.clientWidth, that.viewerDom.clientHeight)
  }
  // 渲染dom
  _readerDom () {
    this.renderer.render(this.scene, this.camera)
    this.labelRenderer.render(this.scene, this.camera)
    this.css3DRenderer.render(this.css3dScene, this.camera)
  }

八、全局动画函数

这里我做了一个全局所有动画的管理器,页面上所有的需要动画的函数都可以传入运行,包括模型的动画、加载水面的运动、贴图的UV动画。

动画函数数组用来存储所有的动画函数

  //动画函数数组
  this.animateEventList = []

对动画函数的添加

  /**
   * 添加全局的动画事件
   * @param animate 函数加参数对象
   * 传入对象 = {
            fun: 函数名称,
            content: 函数参数
        }
   */
  addAnimate (animate) {
    this.animateEventList.push(animate)
  }

这里以状态监视器为例,创建函数,并且添加到全局的动画函数数组里面去

  /**
   * 状态更新
   * @param statsControls
   */
  _statsUpdate (statsControls) {
    statsControls.update()
  }
  /**
   * 添加状态监测
   */
  addStats () {
    if (!this.statsControls) this.statsControls = new Stats()
    this.statsControls.dom.style.position = 'absolute'
    this.viewerDom.appendChild(this.statsControls.dom)
    // 添加到动画
    this.statsUpdateObject = {
      fun: this._statsUpdate, // 函数名称,函数在上面
      content: this.statsControls // 绑定传入的参数
    }
    this.addAnimate(this.statsUpdateObject)
  }

对于函数的移除

  /**
   * 移除全局的动画事件
   * @param animate 函数加参数对象
   * 传入对象 = {
            fun: 函数名称,
            content: 函数参数
        }
   */
  removeAnimate (animate) {
    this.animateEventList.map((val, i) => {
      if (val === animate) this.animateEventList.splice(i, 1)
    })
  }

以移除状态监视器为例

  /**
   * 移除状态检测
   */
  removeStats () {
    if (this.statsControls) this.viewerDom.removeChild(this.statsControls.dom)
    // 添加到动画
    this.statsUpdateObject = {
      fun: this._statsUpdate,
      content: this.statsControls
    }
    this.removeAnimate(this.statsUpdateObject)
  }

九、销毁页面

  beforeDestroy () {
    this.scene.traverse((child) => {
      if (child.material) {
        child.material.dispose()
      }
      if (child.geometry) {
        child.geometry.dispose()
      }
      child = null
    })
    this.renderer.forceContextLoss()
    this.renderer.dispose()
    this.scene.clear()
  }

以上就是针对核心Viewer库封装的一些记录,也不知道写得行不行,但是里面写得一些也是在工作应用当中遇到的一些真实问题,更多关于ThreeJS核心库Viewer封装DS-SDK的资料请关注我们其它相关文章!

(0)

相关推荐

  • Three.js引入Cannon.js及使用示例详解

    目录 引言 大体代码及效果 Cannon.js 打造当前 UI 引言 在开始之前,我们还是要解释下什么是 Cannon.js 以及它的作用. Cannon.js 是一个 3D 物理引擎,通过为物体赋予真实的物理属性的方式来计算运动.旋转和碰撞检测.Cannon.js 相较于其他常见的物理引擎来说,比较轻量级而且完全通过 JavaScript 来实现. Cannon.js 的官方文档地址为 schteppe.github.io/cannon.js/ ,从官方介绍中也可以看到很多有趣的例子,如下所示

  • 解决threeJS加载obj gltf模型后颜色太暗的方法

    目录 网上找到的部分解决方法 效果对比 总结 网上找到的部分解决方法 其实通过查找后不难发现网上给出了很多解决方法,但是大部分都无法从根本上解决问题.我之前看到有一篇文章对gltf的解决方法是让gltf增加自发光,相关的设置如下: 使用threeJS的过程中,刚开始总是会遇到些问题,就比如加载obj/gltf等带材质的模型时老是会出现显示效果较暗的问题. object.traverse((child) => { if(child.isMesh) { child.material.emissive

  • three.js创造时空裂缝特效实现示例

    目录 效果图 建模 多边形形状 随机多边形 漂浮动画 光照 后期处理 效果图 最近受到轮回系作品<寒蝉鸣泣之时>中时空裂缝场景的启发,我用three.js实现了一个实时渲染的时空裂缝场景.本文将简要地介绍下实现该效果的要点. 以下特效全屏观看效果最佳~ <div id="sketch"></div> <div> <div class="fixed z-5 top-0 left-0 loader-screen w-scree

  • threejs中使用drawbufferss示例详解

    目录 原因 历程 原生的使用 基本流程 灵光乍现 使用WebGLMultipleRenderTargets 原因 深度剥离实现之后,似乎会使得走样严重起来. 我意识到,这是因为 剥离这个过程,并没有什么讲究,只要是深度小于等于就剔除了,这样很可能就导致了,原本平滑的差值过渡出现了断层,突变. 简单的解决办法就是增顶点数. 一番搜寻weight oit算法的demo,但是只找到了用原生webgl写的,传送门.在费了几个日夜之后,终于看懂了,但是,还要把它用three实现.一般来说,没有使用编译的框

  • vue+three.js实现炫酷的3D登陆页面示例详解

    目录 前言: Three.js的基础知识 关于场景 关于光源 关于相机(重要) 关于渲染器 完善效果 创建一个左上角的地球 使地球自转 创建星星 使星星运动 创建云以及运动轨迹 使云运动 完成three.js有关效果 结语 前言: 大家好,我是xx传媒严导(xx这两个字请自行脑补) . 该篇文章用到的主要技术:vue3.three.js 我们先看看成品效果: 高清大图预览(会有些慢): 座机小图预览: 废话不多说,直接进入正题 Three.js的基础知识 想象一下,在一个虚拟的3D世界中都需要什

  • three.js镜头追踪的移动效果实例

    目录 达到效果 实现思路 实现难点 1.折现变曲线 2.镜头朝向不受控 3.镜头位置绑定不受控 4.镜头抖动 最终实现方法 方法一:镜头沿线推进 方法二:使用tween动画 方法比较 其他方法 方法一:绘制一条折线+animate镜头推进 方法二:绘制多条线段+animate镜头推进 方法三:绘制多条线段+tween动画变化镜头 方法四:优化方法一,绘制一条折线+animate镜头推进 达到效果 指定一条折线路径,镜头沿着路径向前移动,类似第一视角走在当前路径上. 实现思路 很简单画一条折线路径

  • DS-SDK封装ThreeJS的三维场景核心库Viewer

    目录 正文 一.ThreeJS-ES6库引入 二.初始化渲染器 三.初始化相机 四.初始化场景 五.初始化鼠标控制器 六.灯光初始化 七.全局渲染的函数-逐帧获取页面大小 八.全局动画函数 九.销毁页面 正文 viewer核心库的封装主要是针对threejs场景进行初始封装,以便多项目复用.具体细节我就不多写了,网上一大堆,但是我发现网上的例子都比较雷同,所以我的这一篇文档会着重从我做过的项目上遇到的一些问题来具体描写,详细请看第七.第八小节,主要是第一我们真实项目中,其实你的渲染页面不是整个页

  • php实现百度云加速API及SDK封装

    百度云加速API参考文档 https://su.baidu.com/help/index.html#/7_kaifazhinan/2_APIcankao-NEW/2_wangzhanjieru/2.1.1_tianjiayuming.md 注意: 官方接口v3和v31有些参数并未实现,或返回的内容和文档描述不符合,所以在封装时交叉使用了2个版本的API,并非码字错漏. /** * Author: rehiy <https://www.rehiy.com> * Update: 2021-04-1

  • ThreeJS从创建场景到使用功能实例详解

    目录 前言 创建场景以及相机 创建一个平面 添加图片 创建线 添加轴线 缩放.定位.以及旋转 添加文字 正交摄像机和透视摄像机的区别 总结 前言 最近公司要做一个2.5D插件,然后自己学旋转角度不太好,然后就使用了THREEJS, 用起来还是比较繁琐的,整体支持不太好,整体都是自己研究,看到写的不好地方勿怪 创建场景以及相机 首先,要创建一个场景,以及一个相机(相机分为透视相机和正交摄像机,区别在后面会解释),代码如下 export default class ThreeComponent ex

  • Java核心库实现AOP过程

    这篇文章是关于Java的一个疑难杂症,通过利用Java核心库实现简单的AOP方法,并把实例代码做了分析对照,以下是全部内容: Spring是一个十分火热开源框架,而AOP(面向切面编程)则是Spring最重要的概念之一,为了更好的理解和学习AOP的思想,使用核心库来实现一次不失为一个好方法. 首先介绍一下AOP的概念,AOP(Aspect Oriented Programming),即面向切面编程,所谓的面向切面编程,就是从一个横切面的角度去设计代码的思想,传统的OOP思想是用封装继承和多态构造

  • Java核心库实现简单的AOP

    Spring是一个十分火热开源框架,而AOP(面向切面编程)则是Spring最重要的概念之一,为了更好的理解和学习AOP的思想,使用核心库来实现一次不失为一个好方法. 首先介绍一下AOP的概念,AOP(Aspect Oriented Programming),即面向切面编程,所谓的面向切面编程,就是从一个横切面的角度去设计代码的思想,传统的OOP思想是用封装继承和多态构造一种纵向的层次关系,但不适合定义横向的关系,而AOP思想则对此进行了很好的补充. 例如日志管理代码往往横向的散布在很多对象层次

  • Python测试框架pytest核心库pluggy详解

    目录 代码案例 实例化: 添加到钩子定义中 (add_hookspecs) 注册插件 register 运行插件 pm.hook.myhook 代码案例 import pluggy # HookspecMarker 和 HookimplMarker 实质上是一个装饰器带参数的装饰器类,作用是给函数增加额外的属性设置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("m

  • Three.JS实现三维场景

    最近在看一些Web3D的内容,觉得如果用纯openGLes写一个简单的3D场景太难了:不过还好,有很多现成的库可以使用. (个人感觉):我知道的经常的是Three.JS和SceneJS.感觉Three.JS资料比较多,貌似好学一些吧:另一个是ScenenJS,感觉官方介绍比较好,适合做一些工程和医学上的模拟,实时性比较好,但是中文资料感觉比较少,不太好学习.我个人看的是Three.JS 学习中用到的一些工具和库:学习中用到一些库,也费了不少时间去整理,下载: 用到的工具:WebStorm,个人感

  • vue3.0 移动端二次封装van-uploader实现上传图片(vant组件库)

    1.前提:业务需求,最多上传6张图片,并可以实现本地预览 2.解决方法:使用vant组件库中的van-uploader实现 3.代码实现 template <div class="upload-oss"> <van-uploader :after-read="onRead" :before-read="beforeRead" :accept="fileType" v-model="fileList&

  • python高并发异步服务器核心库forkcore使用方法

    1 拷贝下面的代码到一个文件,并命名为forkcore.py 复制代码 代码如下: import osimport threadingimport selectimport socket class ds_forkcore(object): #async IO(epoll)    def ds_epoll(self):        epoll=select.epoll()        epoll.register(self.s.fileno(),select.EPOLLIN|select.E

  • vue3中如何用threejs画一些简单的几何体

    目录 前言 threejs简述 依赖包版本 vue3操作DOM 创建场景,相机,渲染器本节及后续都在initThree方法中写 立方体 球体 圆柱体 坐标系 点光源 鼠标操作旋转,缩放 球体,立方体自动旋转 initThree完整代码 总结 前言 在vue3中使用threejs画了几个最简单的几何体,自动旋转的立方体,圆柱体,球体,并且加入了光照,几何体影阴部分即光没照到的地方,成果如下,感兴趣的可以看看具体实现过程~ threejs简述 Three.js是基于原生WebGL封装运行的三维引擎

随机推荐