增加了 默认免费插件 resourceManager

This commit is contained in:
hawk86104 2025-02-05 10:40:53 +08:00
parent a9589c8ff4
commit 2f85b804a0
11 changed files with 542 additions and 2 deletions

3
.gitignore vendored
View File

@ -33,12 +33,11 @@ public/plugins/tvtSubstation
src/plugins/networkLinkTopology
public/plugins/networkLinkTopology
# 排除resourceManager、 tvtCharts、showCabinet、tvtVolumeRendering、dxf2mesh、useViewportGizmo、metaHuman、freeDigitalHome 等插件 <但可演示> 可通过插件中心下载
# 排除tvtCharts、showCabinet、tvtVolumeRendering、dxf2mesh、useViewportGizmo、metaHuman、freeDigitalHome 等插件 <但可演示> 可通过插件中心下载
src/plugins/tvtViewHelper
public/plugins/tvtViewHelper
src/plugins/tvtSceneCreator
public/plugins/tvtSceneCreator
src/plugins/resourceManager
src/plugins/tvtCharts
public/plugins/tvtCharts
src/plugins/showCabinet

View File

@ -0,0 +1,73 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-11-26 10:11:19
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-11-27 11:59:34
-->
<template>
<primitive :object="emitters" />
<primitive :object="batchSystem" :position="position" :scale="scale" :rotation="rotation" />
</template>
<script lang="ts" setup>
import * as THREE from 'three'
import * as TQK from 'three.quarks'
import { Resource } from 'PLS/resourceManager'
import { useRenderLoop } from '@tresjs/core'
import { watch } from 'vue'
const props = withDefaults(
defineProps<{
color?: string
position?: Array<number>
scale?: Array<number> | number
rotation?: Array<number>
}>(),
{
color: '#00ffff',
position: [0, 0, 0] as any,
scale: 1,
rotation: [0, 0, 0] as any,
},
)
const getPropsColor = (a: number) => {
const colorThree = new THREE.Color(props.color)
const tv4color = new THREE.Vector4(colorThree.r, colorThree.g, colorThree.b, a) as any
const colorRange = new TQK.ConstantColor(tv4color)
return colorRange
}
const batchSystem = new TQK.BatchedRenderer()
const emitters = new THREE.Group()
const obj = Resource.getItem('CartoonMagicZone.json').clone(true)
obj.traverse((child: any) => {
if (child.type === 'ParticleEmitter') {
const childSystem = child.system
childSystem.startColor = getPropsColor(childSystem.startColor.color.w)
batchSystem.addSystem(childSystem)
}
})
if (obj.type === 'ParticleEmitter') {
batchSystem.addSystem(obj.system)
}
// TQK.QuarksUtil.addToBatchRenderer(obj, batchSystem)
// TQK.QuarksUtil.play(obj)
emitters.add(obj)
const { onLoop } = useRenderLoop()
onLoop(({ delta }) => {
batchSystem.update(delta)
})
watch(
() => [props.color],
([color]) => {
batchSystem.systemToBatchIndex.forEach((value, ps) => {
;(ps as any).startColor = getPropsColor((ps as any).startColor.color.w)
})
},
)
</script>

View File

@ -0,0 +1,52 @@
<script setup lang="ts">
import { watch } from 'vue'
import { Resource } from 'PLS/resourceManager'
import { useRenderLoop } from '@tresjs/core'
const props = defineProps<{
planet: any
}>()
const { scene } = Resource.getItem('airplane.gltf')
const airplane = scene
airplane.rotation.set(0, Math.PI, 0)
scene.traverse((child: any) => {
if (child.isMesh) {
child.castShadow = true
}
})
airplane.updateMatrixWorld()
const { onLoop } = useRenderLoop()
watch(
() => props.planet,
(planet) => {
if (!planet) return
planet.geometry.computeBoundingSphere()
const radius = Math.abs(planet.geometry.boundingSphere?.radius | 1)
airplane.position.set(radius, 0, 0)
airplane.lookAt(planet.position)
},
)
let angle = 0
const speed = 0.2
onLoop(({ delta }) => {
if (!airplane || !props.planet) return
const radius = Math.abs(props.planet.geometry.boundingSphere.radius) + 0.5
angle += delta * speed
const x = radius * Math.cos(angle)
const z = radius * Math.sin(angle)
airplane.position.x = x
airplane.position.z = z
airplane.rotation.z = -Math.PI / 2
airplane.rotation.y = -angle
airplane.updateMatrixWorld()
})
</script>
<template>
<primitive :object="airplane" />
</template>

View File

@ -0,0 +1,55 @@
<script setup lang="ts">
import { watch } from 'vue'
import { Resource } from 'PLS/resourceManager'
import { useRenderLoop } from '@tresjs/core'
const props = defineProps<{
planet: any
}>()
const { scene } = Resource.getItem('cloud.gltf')
const cloud = scene.children[0] as any
cloud.castShadow = true
function random(min: number, max: number): number {
const randomNumber = Math.random() * (max - min) + min
return Math.random() < 0.5 ? -randomNumber : randomNumber
}
cloud.position.set(random(-8, 8), random(0.5, 1), random(-8, 8))
const size = random(0.5, 1)
cloud.scale.set(size, size, size)
cloud.updateMatrixWorld()
watch(
() => props.planet,
(planet) => {
if (!planet) return
cloud.lookAt(planet.position)
cloud.updateMatrixWorld()
},
)
const { onLoop } = useRenderLoop()
let angle = random(-1, 1) * Math.PI
const speed = Math.random() / 10
onLoop(({ delta }) => {
if (!cloud) return
const radius = Math.abs(props.planet.geometry.boundingSphere.radius - 0.5)
angle += delta * speed
const x = radius * Math.cos(angle)
const z = radius * Math.sin(angle)
cloud.position.x = x
cloud.position.z = z
cloud.rotation.y = -angle
cloud.lookAt(props.planet.position)
cloud.updateMatrixWorld()
})
</script>
<template>
<primitive :object="scene" cast-shadow />
</template>

View File

@ -0,0 +1,32 @@
<script setup lang="ts">
import { Resource } from 'PLS/resourceManager'
import { useRenderLoop } from '@tresjs/core'
import Airplane from './airplane.vue'
import Cloud from './cloud.vue'
const { nodes } = Resource.getItem('planet.gltf')
const planet = nodes.Planet
const icosphere = nodes.Icosphere
planet.traverse((child: any) => {
if (child.isMesh) {
child.receiveShadow = true
}
})
const { onLoop } = useRenderLoop()
onLoop(({ delta }) => {
if (!planet) return
planet.rotation.y += delta * 0.04
planet.rotation.z += delta * 0.02
planet.rotation.x += delta * 0.05
planet.updateMatrixWorld()
})
</script>
<template>
<primitive :object="planet" />
<Airplane :planet="icosphere" />
<Cloud v-for="cloud of [1, 2, 3, 4, 5, 6, 7, 8, 9]" :key="cloud" :planet="icosphere" />
</template>

View File

@ -0,0 +1,98 @@
<template>
<div
v-if="!Resource.hasAllFinished.value"
class="absolute bg-grey-600 t-0 l-0 w-full h-full z-99999999 flex justify-center items-center text-black font-mono bg-black"
>
<div class="text-white">
<div class="loader">
<svg viewBox="0 0 800 600" xml:space="preserve">
<symbol id="single">
<path
d="M357.5,211.693c0,35.741,16.598,67.6,42.5,88.307
c25.902-20.707,42.5-52.566,42.5-88.307s-16.598-67.6-42.5-88.307C374.098,144.094,357.5,175.953,357.5,211.693z"
/>
</symbol>
<g id="leaf">
<use class="flo" v-for="index in 36" :key="index" xlink:href="#single" />
</g>
</svg>
</div>
<span class="pspan" v-if="showProgress">{{ Resource.progress.value }} %</span>
</div>
</div>
</template>
<script setup lang="ts">
import { Resource } from 'PLS/resourceManager'
const props = withDefaults(
defineProps<{
isDemo?: boolean
showProgress?: boolean
}>(),
{
isDemo: false,
showProgress: true,
},
)
const animloop = () => {
if (Resource.progress.value++ > 100) {
Resource.progress.value = 0
}
requestAnimationFrame(animloop)
}
if (props.isDemo) {
requestAnimationFrame(animloop)
}
</script>
<style lang="scss" scoped>
#leaf {
fill-opacity: 0.56;
fill: #5384ff;
}
@for $i from 0 through 35 {
.flo:nth-child(36n + #{$i}) {
animation: leaf#{$i} 0.1 * 36s 0s ease both infinite;
}
@keyframes leaf#{$i} {
0% {
opacity: 0;
transform: rotate(($i - 1) * 10deg);
transform-origin: 400px 300px;
}
#{calc(($i) / 35)*100}% {
opacity: 0;
transform: rotate(($i - 1) * 10deg);
transform-origin: 400px 300px;
}
#{calc($i / 35)*100 + 0.2}% {
opacity: 0.3;
transform: rotate($i * 10deg);
transform-origin: 400px 300px;
}
100% {
opacity: 0.3;
transform: rotate($i * 10deg);
transform-origin: 400px 300px;
}
}
}
.loader {
width: 400px;
}
.pspan {
text-align: center;
width: 100%;
display: block;
margin-top: -50px;
}
</style>

View File

@ -0,0 +1,38 @@
/*
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-11-26 09:58:13
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-12-03 11:57:25
*/
export default {
"name": "resourceManager",
"title": "资源管理器插件",
"intro": `适用于TvT.js的资源管理器插件结合loading管理器预加载模型和材质等资源。使用方法详情请见
<a style="color: #5384ff;" href="https://www.icegl.cn/tvtstore/resourceManager" target="_blank">资源管理器插件</a>`,
"version": "1.1.1",
"author": '地虎降天龙',
"website": 'https://gitee.com/hawk86104',
"state": 'active',
"creatTime": '2024-08-09',
"updateTime": '2024-09-10',
"tvtstore": 'FREE',
"require": [],
"preview": [
{
src: `
1全局预加载所有资源Resource.loadResources()</br>
2loading加载等待页</br>
3使用已加载资源Resource.getItem()</br>`,
type: 'text', "name": "simpleLoading", "title": "简单加载实例", disableSrcBtn: true
},
{
src: `
此实例使用了自定义loader:TQK.QuarksLoader</br>
只需要增加这行代码Resource.loaderMapping.QuarksLoader = TQK.QuarksLoader</br>
详细代码查看插件说明或插件用例</br>`,
type: 'text', "name": "customLoading", "title": "自定义loader加载实例", disableSrcBtn: true
},
]
}

View File

@ -0,0 +1,3 @@
import Resource from './lib/Resource'
export { Resource }

View File

@ -0,0 +1,89 @@
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
import { useLoader } from '@tresjs/core'
import { ref } from 'vue'
const loaderMapping: { [key: string]: any } = {
GLTFLoader: GLTFLoader,
TextureLoader: THREE.TextureLoader,
STLLoader: STLLoader,
RGBELoader: RGBELoader,
FileLoader: THREE.FileLoader,
}
class Resource {
decoderPath: string
items: Record<string, any>
hasAllFinished = ref(false)
progress = ref(0)
lenth = 0
curIndex = 0
loaderMapping = loaderMapping
// private setLoadingManager() {
// THREE.DefaultLoadingManager.onStart = function (url, itemsLoaded, itemsTotal) {
// console.log('开始加载文件: ' + url + '.\n已加载 ' + itemsLoaded + ' of ' + itemsTotal + ' 文件.')
// }
// THREE.DefaultLoadingManager.onLoad = function () {
// console.log('加载完成!')
// }
// THREE.DefaultLoadingManager.onProgress = function (url, itemsLoaded, itemsTotal) {
// console.log('加载文件中: ' + url + '.\n已加载 ' + itemsLoaded + ' / ' + itemsTotal + ' 文件.')
// }
// THREE.DefaultLoadingManager.onError = function (url) {
// console.error('加载资源文件错误:' + url)
// }
// }
constructor({ decoderPath = './draco/' } = {}) {
this.decoderPath = decoderPath
// this.setLoadingManager()
this.items = {}
}
loadResources(list: Array<{ functionName: string; url: string; resourceID?: string }>) {
list.forEach(({ functionName, url, resourceID }) => {
this.loadItem(functionName, url, resourceID)
})
}
loadItem(functionName: string, url: string, resourceID: string = '') {
const loaderFunction = this.loaderMapping[functionName]
if (loaderFunction === undefined) {
console.error(`找不到对应的loader${functionName}`)
return
}
if (!resourceID) {
const match = url.match(/[^\\/]+$/)
resourceID = match ? match[0] : url
}
let initDraco = null as any
this.curIndex++
this.lenth++
if (functionName === 'GLTFLoader') {
initDraco = (loader: any) => {
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath(this.decoderPath)
dracoLoader.preload()
loader.setDRACOLoader(dracoLoader)
}
}
const onProgress = (event: any) => {
console.log(`${resourceID}文件加载进度:${Math.floor((event.loaded / event.total) * 100)}%`)
}
useLoader(loaderFunction, url, initDraco, onProgress).then((data: any) => {
this.items[resourceID] = data
this.curIndex--
this.progress.value = Math.floor((this.lenth - this.curIndex) / this.lenth * 100)
if (this.curIndex === 0) {
this.hasAllFinished.value = true
}
})
}
getItem(resourceID: string) {
return this.items[resourceID]
}
}
const instance = new Resource()
// Object.freeze(instance)
export default instance

View File

@ -0,0 +1,69 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-11-26 10:11:13
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-11-27 11:53:24
-->
<template>
<loading useResourceManager />
<TresCanvas clearColor="#201919" window-size>
<TresPerspectiveCamera :position="[5, 5, 5]" :fov="45" :near="0.1" :far="10000" />
<OrbitControls enableDamping />
<cartoonMagic v-if="Resource.hasAllFinished.value" v-bind="configState" :position="[0, 0, 0]" />
<cartoonMagic v-if="Resource.hasAllFinished.value" color="red" :position="[3, 0, 0]" :rotation="[-Math.PI, 1, 45]" />
<cartoonMagic v-if="Resource.hasAllFinished.value" color="green" :position="[-2, 0, 0]" />
<TresMesh :position="[3, 0, 0]">
<TresSphereGeometry :args="[1, 32, 32]" />
<TresMeshBasicMaterial color="red" />
</TresMesh>
<TresMesh :position="[-2, 0, 0]">
<TresSphereGeometry :args="[1, 32, 32]" />
<TresMeshBasicMaterial color="green" />
</TresMesh>
<TresMesh :position="[0, 0, 0]">
<TresSphereGeometry :args="[1, 32, 32]" />
<TresMeshBasicMaterial color="white" />
</TresMesh>
<Suspense>
<reflectorDUDV :position="[0, -0.5, 0]" v-bind="reflectorState" />
</Suspense>
</TresCanvas>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import * as TQK from 'three.quarks'
import { Resource } from 'PLS/resourceManager'
import { yangyangLoading as loading } from 'PLS/UIdemo'
import { OrbitControls } from '@tresjs/cientos'
import { Pane } from 'tweakpane'
import { reflectorDUDV } from 'PLS/floor'
import cartoonMagic from '../components/forCustomLoading/cartoonMagic.vue'
const reflectorState = reactive({
reflectivity: 0.1,
showGridHelper: true,
scale: 1,
})
const configState = reactive({
color: '#ffffff',
scale: 1,
})
Resource.loaderMapping.QuarksLoader = TQK.QuarksLoader
Resource.loadResources([{ functionName: 'QuarksLoader', url: './plugins/floor/json/CartoonMagicZone.json' }])
const paneControl = new Pane()
paneControl.addBinding(configState, 'color', { label: '颜色' })
paneControl.addBinding(configState, 'scale', {
label: '大小',
min: 0.1,
max: 3.0,
step: 0.1,
})
</script>

View File

@ -0,0 +1,32 @@
<template>
<loading useResourceManager />
<TresCanvas v-bind="state" window-size>
<TresPerspectiveCamera :position="[0, 0.5, 3]" :fov="75" :near="0.1" :far="1000" />
<OrbitControls />
<TresAmbientLight color="#484068" :intensity="1" />
<TresPointLight color="#1BFFEF" :position="[0, 0, -8]" :intensity="80" cast-shadow />
<TresDirectionalLight :position="[0, 2, 4]" :intensity="3" cast-shadow :shadow-mapSize-width="2048" :shadow-mapSize-height="2048" />
<Stars :radius="50" :depth="50" :count="5000" :size="0.3" :size-attenuation="true" />
<Planet v-if="Resource.hasAllFinished.value" />
</TresCanvas>
</template>
<script setup lang="ts">
import { OrbitControls, Stars } from '@tresjs/cientos'
import { Resource } from 'PLS/resourceManager'
import { yangyangLoading as loading } from 'PLS/UIdemo'
import Planet from '../components/forSimpleLoading/planet.vue'
const state = {
alpha: false,
clearColor: '#11101B',
shadows: true,
useLegacyLights: true,
}
Resource.loadResources([
{ functionName: 'GLTFLoader', url: './plugins/earthSample/model/lowpolyPlanet/planet.gltf' },
{ functionName: 'GLTFLoader', url: './plugins/earthSample/model/lowpolyPlanet/airplane.gltf' },
{ functionName: 'GLTFLoader', url: './plugins/earthSample/model/lowpolyPlanet/cloud.gltf' },
])
</script>