Skip to content

Commit

Permalink
feat: 给 three-utils 的 *Collection 中的函数添加状态
Browse files Browse the repository at this point in the history
  • Loading branch information
stupidZhu committed Jan 10, 2024
1 parent d1f70cf commit 98d7681
Show file tree
Hide file tree
Showing 20 changed files with 1,549 additions and 396 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ dist
**/.dumi/tmp
**/.dumi/tmp-production

/apps/study-webgl
/playground/*
2 changes: 1 addition & 1 deletion packages/zxtool-three-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@types/lodash": "^4.14.185",
"@types/node": "^18.7.18",
"@types/rollup-plugin-auto-external": "^2.0.2",
"three": "0.158.0",
"cesium": "^1.111.0",
"cross-env": "^7.0.3",
"esbuild": "^0.15.7",
Expand All @@ -43,6 +42,7 @@
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-esbuild": "^4.10.1",
"rollup-plugin-terser": "^7.0.2",
"three": "0.158.0",
"tsconfig": "workspace:*",
"typescript": "^5.2.2"
},
Expand Down
1 change: 1 addition & 0 deletions packages/zxtool-three-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./util/LoaderUtil"
export * from "./widget/CustomGridHelper"
export * from "./widget/threeHelper/ThreeHelper"
export * from "./widget/threeHelper/plugins"
19 changes: 15 additions & 4 deletions packages/zxtool-three-utils/src/util/LoaderUtil.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import * as THREE from "three"
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"

const textureLoader = new THREE.TextureLoader()
const cubeTextureLoader = new THREE.CubeTextureLoader()
const rgbeLoader = new RGBELoader()
const dracoLoader = new DRACOLoader()
const gltfLoader = new GLTFLoader()

dracoLoader.setDecoderPath("/draco/")
gltfLoader.setDRACOLoader(dracoLoader)

export const LoaderUtil = {
gltfLoader: new GLTFLoader(),
textureLoader: new THREE.TextureLoader(),
cubeTextureLoader: new THREE.CubeTextureLoader(),
rgbeLoader: new RGBELoader(),
textureLoader,
cubeTextureLoader,
rgbeLoader,
dracoLoader,
gltfLoader,
}
3 changes: 3 additions & 0 deletions packages/zxtool-three-utils/src/util/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { genInfo } from "@zxtool/utils/dist/util"

export const genZTUInfo = genInfo("@zxtool/three-utils")
54 changes: 54 additions & 0 deletions packages/zxtool-three-utils/src/widget/CustomGridHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as THREE from "three"

export interface CustomGridHelperProps {
xSize?: number
xCount?: number
ySize?: number
yCount?: number
lineColor?: THREE.ColorRepresentation
centerLineColor?: THREE.ColorRepresentation
}

export class CustomGridHelper extends THREE.LineSegments {
type = "CustomGridHelper"

constructor(props: CustomGridHelperProps = {}) {
const { xSize = 1, xCount = 10, ySize = 1, yCount = 10, lineColor = 0x888888, centerLineColor = 0x444444 } = props

const lineColorArray = new THREE.Color(lineColor).toArray()
const centerLineColorArray = new THREE.Color(centerLineColor).toArray()

const xHalf = (xCount * xSize) / 2
const yHalf = (yCount * ySize) / 2

const vertices: number[] = []
const colors: number[] = []

for (let x = -xHalf; x <= xHalf; x += xSize) {
vertices.push(x, 0, -yHalf, x, 0, yHalf)
const colorArr = x === 0 ? centerLineColorArray : lineColorArray
colors.push(...colorArr, ...colorArr)
}
for (let y = -yHalf; y <= yHalf; y += ySize) {
vertices.push(-xHalf, 0, y, xHalf, 0, y)
const colorArr = y === 0 ? centerLineColorArray : lineColorArray
colors.push(...colorArr, ...colorArr)
}

const geometry = new THREE.BufferGeometry()
geometry.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3))
geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3))

const material = new THREE.LineBasicMaterial({ vertexColors: true, toneMapped: false })

super(geometry, material)
}

dispose() {
this.geometry.dispose()
// @ts-ignore
this.material.dispose()
}
}

new CustomGridHelper({})
24 changes: 16 additions & 8 deletions packages/zxtool-three-utils/src/widget/threeHelper/ThreeHelper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { EmitterHelper } from "@zxtool/utils"
import { AnimationItem, ClickItem, ThreeHelperPlugin, ThreeHelperPluginProps } from "./plugins"
import AnimationPlugin from "./plugins/AnimationPlugin"
import ResizePlugin from "./plugins/ResizePlugin"
import ThreeBasePlugin from "./plugins/ThreeBasePlugin"
import {
AnimationWithState,
ClickWithState,
FunctionWithState,
StateCbCollection,
ThreeHelperPlugin,
ThreeHelperPluginProps,
} from "./plugins"
import { AnimationPlugin } from "./plugins/AnimationPlugin"
import { ResizePlugin } from "./plugins/ResizePlugin"
import { ThreeBasePlugin } from "./plugins/ThreeBasePlugin"

export interface ThreeHelper {
getWidget(type: "scene"): THREE.Scene | undefined
Expand All @@ -20,13 +27,14 @@ export class ThreeHelper {
private readonly KEY: PropertyKey = Symbol("TH")
private readonly emitter = new EmitterHelper({ maxCount: { history: 1 } })
private readonly initializedCache: Map<PropertyKey, boolean> = new Map()
private readonly clearCollection: Map<PropertyKey, Function> = new Map()
private readonly clearCollection: StateCbCollection<PropertyKey, FunctionWithState> = new Map()
private readonly widgetCollection: Map<PropertyKey, any> = new Map()

readonly time = { value: 0 }
readonly animationCollection: Map<PropertyKey, AnimationItem> = new Map()
readonly clickCollection: Map<PropertyKey, ClickItem> = new Map()
readonly resizeCollection: Map<PropertyKey, Function> = new Map()
readonly animationCollection: StateCbCollection<PropertyKey, AnimationWithState> = new Map()
readonly clickCollection: StateCbCollection<PropertyKey, ClickWithState> = new Map()
readonly resizeCollection: StateCbCollection<PropertyKey, FunctionWithState> = new Map()
readonly pluginCollection: Map<PropertyKey, ThreeHelperPlugin> = new Map()

getWidget(key: PropertyKey): any {
return this.widgetCollection.get(key)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { throttle } from "lodash"
import * as THREE from "three"
import type { ThreeHelperPlugin, ThreeHelperPluginProps } from "."

class AnimationPlugin implements ThreeHelperPlugin {
export class AnimationPlugin implements ThreeHelperPlugin {
private key = Symbol.for("animation")
private animationId = { value: 0 }

Expand All @@ -15,24 +16,32 @@ class AnimationPlugin implements ThreeHelperPlugin {
const animation = (t = 0) => {
time.value = t
const delta = clock.getDelta()
animationCollection.forEach(fn => fn(t, delta))
animationCollection.forEach<{ _throttled?: boolean }>(item => {
const { fn, state = {} } = item
if (state.throttleTime && !state._throttled) {
fn({ time: t, delta, state })
item.fn = throttle(item.fn, state.throttleTime)
state._throttled = true
} else fn({ time: t, delta, state })
})
this.animationId.value = requestAnimationFrame(animation)
}
animation()

clearCollection.set(this.key, () => {
cancelAnimationFrame(this.animationId.value)
time.value = 0
animationCollection.clear()
initializedCache.set(this.key, false)
clearCollection.set(this.key, {
fn: () => {
cancelAnimationFrame(this.animationId.value)
time.value = 0
animationCollection.clear()
initializedCache.set(this.key, false)
},
})

initializedCache.set(this.key, true)
}

remove({ clearCollection }: ThreeHelperPluginProps): void {
clearCollection.get(this.key)?.()
const clearObj = clearCollection.get(this.key)
if (clearObj) clearObj.fn({ state: clearObj.state ?? {} })
}
}

export default AnimationPlugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as THREE from "three"
import { ThreeHelperPlugin, ThreeHelperPluginProps } from "."
import { genZTUInfo } from "../../../util/util"

const genInfo = genZTUInfo("CameraPlugin")

export class CameraPlugin implements ThreeHelperPlugin {
private key = Symbol.for("animation")
private _camera: THREE.Camera
private addProps!: ThreeHelperPluginProps

get camera() {
return this.camera
}
set camera(c: THREE.Camera) {
if (!this.addProps) throw new Error(genInfo("设置 camera 之前需要先添加此插件"))
const { widgetCollection, emitter } = this.addProps

this._camera = c
widgetCollection.set("camera", c)
emitter.emit("camera", c)
}

constructor() {
this._camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1e4)
this._camera.position.set(5, 5, 5)
}

add(props: ThreeHelperPluginProps): CameraPlugin {
this.addProps = props
const { widgetCollection, emitter, threeHelper } = props

const plugin = threeHelper.pluginCollection.get(this.key) as CameraPlugin
if (plugin) {
console.error(genInfo("已经存在一个 CameraPlugin, 不能重复添加"))
return plugin
}

widgetCollection.set("camera", this.camera)
emitter.emit("camera", this.camera)

return this
}

remove(): void {
if (!this.addProps) throw new Error(genInfo("未添加的插件不能被移除"))

const { widgetCollection, emitter } = this.addProps

widgetCollection.delete("camera")
emitter.clearHistory("camera")
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { LikeDom } from "@zxtool/utils"
import * as THREE from "three"
import type { ThreeHelperPlugin, ThreeHelperPluginProps } from "."

type LikeDom = HTMLElement | typeof window | Document

class ClickPlugin implements ThreeHelperPlugin {
export class ClickPlugin implements ThreeHelperPlugin {
private key = Symbol.for("click")
private cc_key = Symbol.for("default_click")
private dom: LikeDom

constructor(dom: LikeDom) {
Expand All @@ -31,31 +31,41 @@ class ClickPlugin implements ThreeHelperPlugin {
raycaster.setFromCamera(mouse, camera)
let res: THREE.Intersection<THREE.Object3D<THREE.Object3DEventMap>>[] | null = null

clickCollection.forEach(({ fn, objs }) => {
clickCollection.forEach(({ fn, state = {} }) => {
const objs = state.objs
if (objs?.length) {
const _res = raycaster.intersectObjects(objs)
if (_res.length) fn(_res, e)
if (_res.length) fn({ objs: _res, e, state })
} else {
if (!res) res = raycaster.intersectObjects(scene.children)
fn(res, e)
fn({ objs: res, e, state })
}
})
}

this.dom.addEventListener("click", clickFn)

clearCollection.set(this.key, () => {
this.dom.removeEventListener("click", clickFn)
clickCollection.clear()
initializedCache.set(this.key, false)
clearCollection.set(this.key, {
fn: () => {
this.dom.removeEventListener("click", clickFn)
clickCollection.clear()
initializedCache.set(this.key, false)
},
})

clickCollection.set(this.cc_key, {
fn({ objs }) {
const mesh = objs?.[0]?.object
// @ts-ignore
if (typeof mesh?.__onClick === "function") mesh.__onClick()
},
})

initializedCache.set(this.key, true)
}

remove({ clearCollection }: ThreeHelperPluginProps): void {
clearCollection.get(this.key)?.()
const clearObj = clearCollection.get(this.key)
if (clearObj) clearObj.fn({ state: clearObj.state ?? {} })
}
}

export default ClickPlugin
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface DevPluginConfig {
axesSize?: number
}

class DevPlugin implements ThreeHelperPlugin {
export class DevPlugin implements ThreeHelperPlugin {
private key = Symbol.for("dev")
private ac_key = Symbol.for("update_stats")
private stats?: Stats
Expand Down Expand Up @@ -36,29 +36,30 @@ class DevPlugin implements ThreeHelperPlugin {
if (enableStats) {
this.stats = new Stats()
document.body.appendChild(this.stats.dom)
animationCollection.set(this.ac_key, () => {
this.stats?.update()
animationCollection.set(this.ac_key, {
fn: () => this.stats?.update(),
})
}

clearCollection.set(this.key, () => {
if (this.stats) {
this.stats.dom.remove()
this.stats = undefined
}
if (this.axesHelper) {
scene.remove(this.axesHelper)
this.axesHelper = undefined
}
initializedCache.set(this.key, false)
clearCollection.set(this.key, {
fn: () => {
if (this.stats) {
this.stats.dom.remove()
this.stats = undefined
}
if (this.axesHelper) {
scene.remove(this.axesHelper)
this.axesHelper = undefined
}
initializedCache.set(this.key, false)
},
})

initializedCache.set(this.key, true)
}

remove({ clearCollection }: ThreeHelperPluginProps): void {
clearCollection.get(this.key)?.()
const clearObj = clearCollection.get(this.key)
if (clearObj) clearObj.fn({ state: clearObj.state ?? {} })
}
}

export default DevPlugin
Loading

0 comments on commit 98d7681

Please sign in to comment.