# base-r3d

based on three.js

* [threejs 官网](https://threejs.org)
* [threejs 文档](https://threejs.org/docs/index.html)
* [threejs examples](https://threejs.org/examples/)

## install

```bash
npm i --save base-r3d
```

## Components List

* [x] Graphic: `Graphic3D、Graphic2D、GraphicBlend`
* [x] Lights: `Light|AmbientLight|DirectionalLight|HemisphereLight|PointLight|RectAreaLight|SpotLight`
* [x] SkyBox
* [x] Camera
* [x] Scene
* [x] Scene2D
* [x] InnerHelper `base-r3d/lib/components/assist/Helper`
* [x] Hooks `EventHooks`
* [x] plugins `DragControls/ObjEditControls...`
* [x] things `Mesh/Line/Line2D/ModelContent/ThingsGroup/ObjectGroup/DrawingPaths`

### Graphic 介绍

系统核心画布，集成 `renderer、camera、scene、orbit`。

支持的全局事件： `stage_fullscreen`，可以采用如下方式触发

```js
import { r3d } from 'base-r3d/lib/r3d';
import { INNER_CONSTS } from 'base-r3d';

const { STAGE_EVENT_TYPE } = INNER_CONSTS;

// 触发全屏
r3d.trigger(STAGE_EVENT_TYPE.FULLSCREEN);
```

## Helpers

* _Error `base-r3d/lib/_core_/_Error`
* _propTypes `base-r3d/lib/_core_/_propTypes`
* Animate `base-r3d/lib/_core_/Animate`
* BaseObject `base-r3d/lib/_core_/BaseObject`
* BaseR3D `base-r3d/lib/_core_/BaseR3D`
* CacheR3D `base-r3d/lib/_core_/CacheR3D`
* properties `base-r3d/lib/_core_/properties`
* resizeConnect `base-r3d/lib/connect/resizeConnect`
* unexpectedLoadingConnect `base-r3d/lib/connect/unexpectedLoadingConnect`
* domeEvents `base-r3d/lib/events/domeEvents`

## Factroy

* CameraFactory `base-r3d/lib/components/factory/cameraFactory`
* CombinedCameraFactory `base-r3d/lib/components/factory/combinedCameraFactory`
* SceneFactory `base-r3d/lib/components/factory/sceneFactory`
* TextureFactory `base-r3d/lib/components/factory/textureFactory`
* ModelFactory `base-r3d/lib/components/factory/modelFactory`
* PickerFactory `base-r3d/lib/components/factory/pickerFactory`
* OutlineFactory `base-r3d/lib/components/factory/outlineFactory`
* PathPenFactory `base-r3d/lib/components/factory/pathPenFactory`
* MarkerFactory `base-r3d/lib/components/factory/markerFactory`
* CSS2DFactory `base-r3d/lib/components/factory/css2DFactory`
* FloorFactory `base-r3d/lib/components/factory/floorFactory`
* LensJumpFactory `base-r3d/lib/components/factory/lensJumpFactory`

```js
// resizeConnect, 获取被包裹组件的 ref

const BigComponent = resizeConnect(MyComponent, { withRef: true })

<BigComponent ref={node => this.bigRef = node} />

// 需要获取到 MyComponent 组件的实例，需要采用如下方法

const myComponent = this.bigRef.getWrappedInstance();
```

## 扩展

* 目录

`base-r3d/lib/third/threejs`

* 列表
  * controls `DragControls|FirstPersonControls|FlyControls|OrbitControls|PointerLockControls|TrackballControls`
  * exts `Color|Line|Object3D|Vector3`
  * loaders `MTLLoader|OBJLoader|CusOBJLoader (add custom Group)`
  * objects `FatLine|MeshLine|RouteLine`
  * render `CSS2DRender`

## 说明

### 核心

### Graphic

* 概述

由于 Renderer/Scene/Camera 三者，是必须元素，因此将三者的创建，放在 `components/graphic` 中，即 `Graphic` 组件。同时给其子组件注入以下 props:

**`__scene__`** 基础场景

**`__camera__`** 核心相机

**`attach`** 将object元素添加至 Scene 场景

**`detach`** 从场景中移除具体的object

**`attachToCamera`** 将object元素添加至 相机

**`detachFromCamera`** 从相机中移除具体的 object

* props

| params | type | default | descr |
| ------ | ------ | ------ | ------ |

> `sceneOptions` 和 `cameraOptions` 必须手动传入。

```js
const directLightPropType = PropTypes.shape({
  option: PropTypes.shape({
    // If enable shadow of main light.
    shadow: PropTypes.bool,
    // Quality of main light shadow. 'low'|'medium'|'high'|'ultra'
    shadowQuality: PropTypes.oneOf(['low', 'medium', 'high', 'ultra']),
    // Intensity of main light
    intensity: PropTypes.number,
    // Color of main light
    color: colorPropTypes,
    // Alpha is rotation from bottom to up.
    alpha: PropTypes.number,
    // Beta is rotation from left to right.
    beta: PropTypes.number
  }),
  // 是否显示辅助器
  showHelper: PropTypes.bool
});

const propTypes = {
...basePropTypes,
  className: PropTypes.string,
  threeContainerClassName: PropTypes.string,
  // 是否启用内部 size，如果设置为true，将会自动绑定 onreszie，同时以父节点的宽高作为canvas的宽高
  enableInnerSize: PropTypes.bool,
  // 是否开启高性能，设置为 true，则会根据条件执行 animate （即：renderer.render() 不会一直处于执行状态）
  highPerformance: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.shape({
      // 空闲检测时间间隔，默认为 60s
      idleDetectDelay: PropTypes.number,
      // 自动开启检测
      autoStart: PropTypes.bool
    })
  ]),
  width: PropTypes.number,
  height: PropTypes.number,
  // 自行设置 size，如果设置为 true，则3D canvas 的大小，有父节点内容区大小决定
  autoSize: PropTypes.bool,
  webglRender: PropTypes.object,
  // THREE.Scene 实例，或者是一个 Scene params
  sceneOptions: sceneOptionsPropTypes,
  // THREE.Camera 实例，或者是一个 Camera params, 当为 Camera 时，需要自行处理resize等事件
  cameraOptions: cameraOptionsPropTypes,
  showStats: PropTypes.bool,
  maskContent: PropTypes.element,
  // 在执行 `renderer.render` 之前执行，用于同步改变其它数据 (renderer, scene, camera) => {}
  beforeRender: PropTypes.func,
  // 在执行 `renderer.render` 之后执行，用于同步改变其它数据 (renderer, scene, camera) => {}
  afterRender: PropTypes.func,
  loading: PropTypes.bool,
  percent: PropTypes.number,
  customLoading: PropTypes.node,
  // { onLoad, onProgress, onError } or THREE.LoadingManager
  loadingManager: PropTypes.object,
  // loadingManger 加载信息，当为`undefined, null, false` 任一，则表示不显示，或者是加载完成
  loadingResInfo: PropTypes.oneOfType([
    PropTypes.oneOf([undefined, null, false]),
    PropTypes.shape({
      total: PropTypes.number,
      current: PropTypes.number,
      url: PropTypes.string
    })
  ]),
  // 渲染loadingResInfo
  renderLoadingResMsg: PropTypes.oneOfType([
    PropTypes.node,
    PropTypes.func
  ]),
  // 显示加载模型之后的应用模型
  showObjSpinner: PropTypes.bool,
  // 显示加载细节
  showLoaderDetails: PropTypes.bool,
  // 启用 CSS2D，当需要设置 2d 页面时，可以启用此项
  enableCSS2D: PropTypes.bool,
  // 启用 OrbitControls
  enableOrbit: PropTypes.bool,
  // OrbitControls 配置信息
  orbitOptions: PropTypes.object,
  // 初始化之后
  afterInit: PropTypes.func,
  // 隐藏 正在渲染 spinner
  hiddenRenderSpinner: PropTypes.bool,
  // renderer 初始化参数
  rendererOptions: PropTypes.object,
  // 添加自定义的插件，(webglRender, scene, camera, r3d) => {}
  addPlugins: PropTypes.func,
  // 最外层 div 原始属性
  nativeProps: PropTypes.object,
  // 3d 包裹层 div 样式
  threeContainerStyle: PropTypes.object,
  // 启用动画插值器
  enableAnimator: PropTypes.bool,
  // 启用描边器
  enableOutline: PropTypes.bool,
  // 启用 obj outline，采用 OutLineHelper 实现
  enableObjOutline: PropTypes.bool,
  // 启用 line 边缘发光
  enableLineBloom: PropTypes.bool,
  posteffects: PropTypes.shape({
    // 颜色校正
    colorConfig: PropTypes.shape({
      exposure: PropTypes.number, // 曝光 -1~1
      brightness: PropTypes.number, // 亮度 -1~1
      contrast: PropTypes.number, // 对比度 0~5
      saturation: PropTypes.number, // 饱和度 0~10
      gamma: PropTypes.number // 伽马校正 0~2
    }),
    // ssao 特效
    ssaoConfig: PropTypes.shape({
      enableSSAO: PropTypes.bool,
      output: PropTypes.number,
      kernelSize: PropTypes.number,
      kernelRadius: PropTypes.number,
      minDistance: PropTypes.number,
      maxDistance: PropTypes.number
    }),
    // 光晕/泛光
    bloomConfig: PropTypes.shape({
      strength: PropTypes.number,
      radius: PropTypes.number,
      threshold: PropTypes.number
    })
  }),
  // 是否采用混合相机
  isBlend: PropTypes.bool,
  // 启动内置灯光池
  enableLightPool: PropTypes.bool,
  // 仅当启用内置灯光池时，才有效，更新灯光池中的光源参数
  lightProps: PropTypes.shape({
    // 主光源 平行光
    mainLight: directLightPropType,
    // 次光源 平行光
    secondLight: directLightPropType,
    // 环境光
    ambientLight: PropTypes.shape({
      color: colorPropTypes,
      intensity: PropTypes.number
    }),
    // 半球光
    hemisphereLight: PropTypes.shape({
      // 天空中发出光线的颜色
      color: colorPropTypes,
      // 地面发出光线的颜色
      groundColor: colorPropTypes,
      intensity: PropTypes.number
    })
  }),
  enablePositionCtl: PropTypes.bool,
  positionCtlProps: PropTypes.shape({
    /**
     * 前置处理选中的 object，
     * 当目标元素是 Group 时，_DragControls 选中的并非是 Group， 此时可以使用该方法进行预处理
     */
    prevProcessTarget: PropTypes.func
  }),

  // 启用 debug 模式，设为true时，将额外渲染 ligth 辅助器
  enableDebug: PropTypes.bool
};
```

> 当设置 `highPerformance` 为 true 时，将会检测当前打开页面是否是空闲状态，空闲状态超时后，将会停止内置动画以及动态渲染。
> 如果推送消息，需要强制渲染，此时又无用户交互，可以采用 `this.stagePilot.prefChecker.resetTask()` 重置空闲，强制渲染。`prefChecker` 只有在 `highPerformance` 才会创建。

### connect3D

采用 HOC 的方式，提供统一的 `onCreated` 方法，将组件的内的 `instance` 暴露至外部，以供动态改变 `Object3D` 属性。

劫持公共属性 `visible`，统一处理所有 `Object3D` 的 `visible` 属性。

### factory

* CameraFactory
* SceneFactory
* TextureFactory

### SkyBox

### InnerControl 内置控制

* 缩略图：鼠标悬浮时，隐藏 grid，点击时根据当前场景，生成截图数据
* 坐标拾取：点击弹出面板，选择是否开启坐标拾取

### utils

## umd 支持

since v1.5.0 之后，新增 `umd` 支持，umd 模式下，需要自行加入的模块有：

* react
* react-dom
* prop-types

建议采用 `webpack` 时，将上述加入到 `externals` 中。

umd 暴露的 library 名为 `B3D`

```js
defaultConfig.externals = {
  ...
  'base-r3d': 'B3D',
  ...
};
```

该 umd 模块，采用 `amnos-build` 的 `umdConfig` 进行创建。

why not `rollup` ? 外部资源抽离有问题，以及 external 不匹配。

## changelog

[changelog](changelog.md)

## Lecense

MIT
