Skip to content

npm package three-editor-cores source code -- 三维场景低代码编辑器内核npm包源码

License

Notifications You must be signed in to change notification settings

z2586300277/three-editor-cores

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

node 18

  • 这是一个 集成 three.js 等依赖的库 build 打包为一个 js 文件 发布到 npm 仓库使用, 专注 编辑器 造轮子
  • API文档不全,自行查看
预览 赞助我
npm install  three-editor-cores 

THREE.js 0.157.0

引入

import { ThreeEditor } from 'three-editor-cores'

const { ThreeEditor } = require('three-editor-cores')

设置draco 解码器路径

ThreeEditor.dracoPath = '/draco/'

js 技巧

/**
 * 挟制监听 
 */

let originalAdd = scene.add

scene.add = function (object) {

  originalAdd.apply(scene, arguments)

}

创建场景

const ThreeEditor = new ThreeEditor({

    threeBoxRef: document.querySelector('#threeBox'), 

    rendererParams: {

        fps: null,  // fps 控制 传 null 不控制, 根据电脑分辨率 HZ

        pixelRatio: window.devicePixelRatio * 1,   // 分辨率参数

        webglRenderParams: { antialias: true, alpha: true, logarithmicDepthBuffer: true },  // 同 three.js WebglRenderer 通用参数 

        userPermissions: {  autoPlace: true, proxy: false }  // 用户权限  autoPlace false 不挂载到页面上  proxy 空对象 代理 dat.gui 

    },

    sceneParams: JSON.parse(localStorage.getItem('sceneParams')), // 场景参数 没有可以不传, 保存后生成

    meshListParams: JSON.parse(localStorage.getItem('meshListParams')), // 物体对象参数 没有可以不传 保存后生成

    skyParams: JSON.parse(localStorage.getItem('skyParams')), // 天空盒子参数  注:此天空盒会同时设置为全局环境贴图 没有可不传 自行生成和保存

    // 编辑器场景保存回调
    saveEditorCallBack: (sceneParams, meshListParams) => {

        localStorage.setItem('sceneParams', JSON.stringify(sceneParams))

        localStorage.setItem('meshListParams', JSON.stringify(meshListParams))

    }

})

threeEditor.viewer  // 包含场景 所有 对象 

threeEditor.progressList  // 初次加载每一个模型进度控制

threeEditor.progressList.forEach(i => i.loaderService.progress = e => yourCallBack(e)) // 将你的回调 挂接获取每一个进度

销毁场景

threeEditor.viewer.destroySceneRender()

适配屏幕

window.onresize = () => threeEditor.viewer.renderSceneResize()

viewer 下属性

transformControls.dragChangeCallback = (v) => {} // 控制器拖拽回调

chartsMapControls.geoGroupLoadCall = (group) => {} // 地理地图加载完成回调 注:重构

chartsMapControls.geoGroupAllLoadedCall = () => {} // 所有地图加载完毕

API

/**
 * e DOM click/dblclick/mousemove/mouseup/mousedown 事件  
 * 
 * info 返回点击相关信息
 */

threeEditor.getSceneEvent(e, (info) => ())

/**
 * 原生未处理事件 group  从 group 中进行查找
 * 
 * return 获取相交所有元素
 */

threeEditor.getRawSceneEvent(e, group)

/**
 * 注:重构
 * 
 * 传递参数
 *
 * { type: 'GLTF', url: 'HOST/yCar.glb' },
 *
 * { type: 'FBX', url: 'HOST/tileset.FBX' },
 *
 * { type: 'OBJ', url: 'HOST/resource/objHouse/house.obj' },
 *
 * 根据传参增加相关mesh 模型对象
 * 
 * return { loaderService, type } 自动push progressList
 */

const { loaderService, rootInfo } = threeEditor.setModelFromInfo({ type: 'GLTF', url: 'HOST/yCar.glb' })

loaderService.progress = e => console.log(e) // 单一进度回调

loaderService.complete = (model) => console.log('加载完成') // 单一加载完成回调

/**
 * 设置天空盒子 图片地址列表 urls
 * 
 * [1.png, 2.png, 3.png, 4.png, 5.png, 6.png]
 */

threeEditor.setSky(urls)

/**
 * 设置全局环境贴图资源
 * 
 * 值同 上  天空盒
 */

threeEditor.setGlobalEnvBackground(urls)

/**
 * 设置二维DOM 元素
 * 
 * DOM 传入的dom元素
 * 
 * point 传入的坐标点
 * 
 * return mesh  属性 destroy() 销毁方法  更新重新调用 setCss2dDOM
 * 
 * 注:移除事件 生成完毕 => dom.style.pointerEvents = 'none'
 */

const mesh = threeEditor.setCss2dDOM(document.querySelector('#your_dom'),point) 

mesh.destroy() 

/**
 * 设置三维DOM 元素
 * 
 * DOM 传入的dom元素
 * 
 * point 传入的坐标点
 * 
 * return mesh  属性 destroy() 销毁方法  更新重新调用 setCss3dDOM
 * 
 * 注:移除事件 生成完毕 => dom.style.pointerEvents = 'none'
 */
 
const mesh = threeEditor.setCss3dDOM(document.querySelector('#your_dom'),point)

mesh.destroy()

/**
 * 计算两点之间的 指定距离比例点
 * 
 * p1, p2 , 比例 , :例如计算相机与点击点之间的 0.5 比例点
 * 
 * return vector3
 */ 

threeEditor.getDistanceScalePoint(camera.position, info.point, 0.5)

/**
 * 补间动画 例如: 对camera.position 视角补间 , controls.target 视角中心补间
 * 
 * vector3 旧的三维向量, vector3_ 更改后的三维向量 可以是对象 { x: 0, y: 0, z: 0 }
 * 
 * gsapQuery { duration: 3, ease: 'none', repeat: 0, yoyo: false , onUpdate: () => {}, onComplete: () =>{} }
 * 
 * duration 动画时间
 * 
 * ease 缓动函数
 * 
 * repeat 重复次数
 * 
 * yoyo 往返播放
 * 
 * onUpdate 动画更新回调
 * 
 * onComplete 动画完成回调
 * 
 * return gsapControl 动画对象 用于控制动画 gsapControl.pause() gsapControl.play() gsapControl.kill()
*/

threeEditor.setGsapAnimation(vector3, vector3_, gsapQuery)

/**
 * 设置GUI DOM 位置  userPermissions: { autoPlace: false}  autoPlace 需要设置成false
 * 
 * DOM 传入的GUI 父级dom元素
 * 
 * return { GUIDom, remove () } 返回GUIDom, 和 dom 移除方法 
 * 
 * 可通过GUIDom.style.display 控制显示隐藏
 */

threeEditor.setGUIDomPosition(DOM)

/**
 * 设置轮廓光选中
 * 
 * model 模型对象 数组形式
 * 
 * 清空传 []
 */

threeEditor.setOutlinePass([model])

/**
 * 保存
 */

threeEditor.saveSceneEditor()

/**
 * 刷新GUI 数据 使GUI 数据与mesh 数据同步
 */

threeEditor.refreshGUI()

/**
 * 场景截图
 * 
 * 例 params = ['image/jpeg', 0.9]  => toDataURL(...params) 
 */

threeEditor.getSceneEditorImage(params)

/**
 * 设置场景模式
 * 
 * mode = '选择', '根选择', '变换', '场景绘制', '点击信息'
 */

threeEditor.setSceneControlMode(mode)

/**
 * 设置控制器属性
 * 
 * showX showY showZ => Boolean, translationSnap rotateSnap scaleSnap => Number  mode => 'translate' || 'rotate' || 'scale'
 */

threeEditor.setTransformControlsProperty('showX', false)

/**
 * 设置操作选项
 *  
 * key = grid || axes || openKey || stats  : value = true || false
 */

threeEditor.setOperateOption('stats', Math.random() > 0.5 ? true : false)

/**
 * 根据参数播放模型动画
 *  
 * 参数 mesh => 加载的模型对象  模型如果存在动画 则mesh 会携带以下属性
 * 
 * animations => 模型动画列表
 * 
 * animationPlayParams => 模型动画播放参数 与GUI一致 修改会进行保存 如下 可自行修改
 * 
 * { initPlay: false, speed: 0.5, actionIndexs: [animations.length], startTime: 0, loop: true, frameCallback: () => { } }
 * 
 * initPlay 是否初始化播放 speed 播放速度 actionIndexs: [需要播放得动画 bool] startTime 播放开始时间 loop 是否循环播放 frameCallback 每一帧回调
 * 
 * return { mixer: 播放器, actions:播放列表 }   暂停/继续 actions.forEach(i => i.paused = !i.paused)  停止:i.stop()  播放:i.play() 
 */

const model = threeEditor.viewer.currentInfo?.currentRootModel

const _actions = Math.random() > 0.5 ? [1, 3, 5, 7] : [2, 4, 6, 8]

model.animationPlayParams.actionIndexs.forEach((_, k, arr) => arr[k] = _actions.includes(k))

const { mixer, actions } = threeEditor.setModelAnimationPlay(model)

mixer.addEventListener('finished', (e) => console.log(123))

/**
 * 移除模型动画
 * 
 * 参数 mesh => 模型对象
 */

threeEditor.removeModelAnimation(mesh)

/**
 * 生成立方体
 * 
 * size 尺寸  color 颜色
 */

threeEditor.setBoxGeometry(size, color)

/**
 * 地理物体 group 使用
 * 
 * 属性 url, materialType 同生成地理地图
 * 
 * geoInfo => 同geojson 数据拷贝加工, geoInfo?.properties?.centerCoord3 地理区块行政中心原三维坐标 
 * 
 * 方法 getTransformedVector(Vector3) => 根据模型转换坐标
 * 
 */

group.children.forEach(i => {

  if (i.geoInfo?.properties?.centerCoord3) {

    const mesh = threeEditor.setBoxGeometry(10, 'red')

    mesh.position.copy(getTransformedVector(i.geoInfo?.properties.centerCoord3))

    threeEditor.viewer.scene.add(mesh)

  }

})

/**
 * 设置物体材质
 * 
 * params = material 参数
 * 
 * mesh.meshRevertMaterial() => 恢复原材质
 */

threeEditor.changeMeshMaterial(group, params)

/**
 * 设置物体变换
 * 
 * params = position, rotation, scale 参数
 * 
 * mesh.meshRevertTransform() => 恢复原变换
 */

threeEditor.changeMeshTransform(group, params)

/**
 * 地图设置浮动变化 注:重构
 * 
 * 变换材质 可使用 changeMeshMaterial Api
 * 
 * changeMeshTransform 可实现物体变换,实际地图场景可能并不适用, 需要特定并结合动画手写
 */

let currnetMeshName = null

let meshs = []

threeEditor.viewer.chartsMapControls.geoGroupLoadCall = (group) => {

  if (group.name !== '带事件') return

  const { raycaster, getIntersects } = threeEditor.getRawSceneEvent()

  raycaster.far = 1000

  document.querySelector('#threeBox').addEventListener('mousemove', (e) => {

    const intersects = getIntersects(e, group.children)

    const i = intersects.find((i) => i.object.text !== 'TransformControls' && i.object.isMesh)

    if (!i) return

    if (currnetMeshName === i.object.name) return

    currnetMeshName = i.object.name

    meshs.forEach(i => {

        i?.meshRevertMaterial()

        i?.meshRevertTransform()

    })

    // 修改形状
    meshs = group.children.filter(j => j.name === i.object.name)

    meshs.forEach(i => {

       threeEditor.changeMeshTransform(i, { scale: { x: 1, y: 1, z: 3 } })

       threeEditor.changeMeshMaterial(i, { color: 'blue', opacity: 1 })

    })

  })

}

/**
 * 三维向量计算  物体变换后结果
 * 
 * point 传入的坐标点 object: { position, rotation, scale }
 */

threeEditor.pointSyncTransform(point, mesh)

/**
 * 获取场景曲线列表
 * 
 * return [{ path, mesh }]
 */

threeEditor.getSceneCurveList()

/**
 * 根据曲线生成曲线动画
 * 
 * 参数 path => 曲线路径 speed => 速度
 * 
 * return { time: 时间 0-1, speed, paused: 暂停, destroy: 销毁, frameCallback:(p) => 每一帧, frameEndCallback: () => 结束 } 实时更新
 * 
 * 注: 返回的此对象并不针对一次动画, 重复动画, 将time 重置为0, paused 重置为false 
 */

threeEditor.setCurveAnimation(curve, 1)

/**
 * 案例: 物体曲线动画
 */

const { mesh, path } = threeEditor.getSceneCurveList()[0] // 获取一条曲线

const curveAnimate = threeEditor.setCurveAnimation(path, 1) // 生成当前曲线的动画控制器

const mesh1 = threeEditor.viewer.scene.getObjectByName('运动')

// 每一帧回调 
curveAnimate.frameCallback = p => {

  // 想要实现何种动画逻辑
  mesh1.position.copy(

    // 坐标点同步
    threeEditor.pointSyncTransform(p, mesh)

  )

}

curveAnimate.start()

/**
 * 自定义物体变换动画 播放
 * 
 * mesh/ group  下的transformAnimationList 为自定义变换动画列表 = [action, action]
 * 
 * action = { name, _transformInfo: 旧变换信息 , transformInfo_: 新变换信息 , gsapParams { mode: gsap 函数方式 , query:  gsapQuery } }
 * 
 * setGsapMeshAction 执行物体的变换动画
 * 
 * 传值 mesh, action._transformInfo, action.transformInfo_, action.gsapParams
 * 
 * return promise => 动画执行
 */

const mesh = threeEditor.viewer.scene.getObjectByName('大楼')

const { transformAnimationList } = mesh

// 时间轴组合如
transformAnimationList.forEach((i, k) => {

  setTimeout(() => {

    i.gsapParams.query.onUpdate = () => { }

    threeEditor.setGsapMeshAction(mesh, i._transformInfo, i.transformInfo_, i.gsapParams)

  }, k * 2000)

})

/**
 * 获取最佳视角
 * 
 * model 模型对象  scale 视角缩放比例 默认2.5
 * 
 * return { target, position }
 */

threeEditor.getBestViewTarget(model, scale)

/**
 * 获取视图api
 * 
 * getObjectViews(object, fov = camera.fov) return { 视图 点} 
 */

threeEditor.getObjectViews(object)

/**
 * 场景根物体根据 前缀进行分组
 * 
 * 参数 prefix =>  '全部' || [ '场景1', '场景2']
 */

threeEditor.setSceneFromClassify(['#1'])

// ---:例 转场
const { camera, controls } = threeEditor.viewer

  const [end, start] = controls.viewAngleList  // 此前预设的两级下转视角

  // 第一次视角切换
  setGsapAnimationLook(start).then(() => {

    // 场景模型切换 天空 等 任意操作
    threeEditor.setSceneFromClassify(['场景2'])

    threeEditor.setSky([])

    // 第二次视角切换
    setGsapAnimationLook(end)

  })

function setGsapAnimationLook(viewAngle) {

  return Promise.all([

    new Promise((resolve) => {

      threeEditor.setGsapAnimation(camera.position, viewAngle.position, { duration: 2, onComplete: resolve })

    }),

    new Promise((resolve) => {

      threeEditor.setGsapAnimation(controls.target, viewAngle.target, { duration: 2, onComplete: resolve })

    })

  ])

}

/**
 * mesh 或 group 进行材质克隆
 * 
 * 增加 isCloneMaterial = true 属性 originMaterial = 原材质 备份
 */

threeEditor.meshGroupCloneMaterial(mesh/group)

/**
 * 额外 API
 * 
 * import { createSkySphereShader, createScanPlane, getLight } from 'three-editor-cores'
 */

createSkySphereShader({ materialType }) // 返回天空球 mesh 属性调节 uniforms

createScanPlane({ materialType, url }) // 返回扫描平面 mesh 属性调节 uniforms

getLight('PointLight') // 返回光源

About

npm package three-editor-cores source code -- 三维场景低代码编辑器内核npm包源码

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published