no message
BIN
public/plugins/tvtSceneCreator/image/backGround/b-black.jpeg
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
public/plugins/tvtSceneCreator/image/backGround/b-blue.jpeg
Normal file
After Width: | Height: | Size: 179 KiB |
BIN
public/plugins/tvtSceneCreator/image/backGround/b-cyan.jpeg
Normal file
After Width: | Height: | Size: 297 KiB |
BIN
public/plugins/tvtSceneCreator/image/backGround/b-green.jpeg
Normal file
After Width: | Height: | Size: 326 KiB |
BIN
public/plugins/tvtSceneCreator/image/backGround/b-red.jpeg
Normal file
After Width: | Height: | Size: 538 KiB |
BIN
public/plugins/tvtSceneCreator/image/backGround/upload.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 7.1 KiB |
BIN
public/plugins/tvtSceneCreator/image/envHDR/desert.jpeg
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/plugins/tvtSceneCreator/image/envHDR/finishHDR.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
public/plugins/tvtSceneCreator/image/envHDR/metro_noord_1k.hdr
Normal file
BIN
public/plugins/tvtSceneCreator/image/envHDR/metro_noord_1k.jpeg
Normal file
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 16 KiB |
BIN
public/plugins/tvtSceneCreator/image/envHDR/shanghai_bund_1k.hdr
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
public/plugins/tvtSceneCreator/preview/index.png
Normal file
After Width: | Height: | Size: 147 KiB |
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<Suspense>
|
||||
<template v-if="envSetup.isLightFormer">
|
||||
<Environment :blur="envSetup.blur" :background="!backgroundSetup.useBackImg" :far="100000">
|
||||
<TresGroup
|
||||
:position="[envSetup.pos.x, envSetup.pos.y, envSetup.pos.z]"
|
||||
:rotation="[envSetup.rotate.x, envSetup.rotate.y, envSetup.rotate.z]"
|
||||
:scale="[envSetup.scale.x, envSetup.scale.y, envSetup.scale.z]"
|
||||
>
|
||||
<Lightformer :intensity="0.75" :rotation-x="Math.PI / 2" :position="[0, 5, -9]" :scale="[10, 10, 1]" />
|
||||
<Lightformer :intensity="4" :rotation-y="Math.PI / 2" :position="[-5, 1, -1]" :scale="[20, 0.1, 1]" />
|
||||
<Lightformer :rotation-y="Math.PI / 2" :position="[-5, -1, -1]" :scale="[20, 0.5, 1]" />
|
||||
<Lightformer :rotation-y="-Math.PI / 2" :position="[10, 1, 0]" :scale="[20, 11, 1]" />
|
||||
<Levioso :speed="5" :floatFactor="2" :rotationFactor="2">
|
||||
<Lightformer form="ring" :color="envSetup.colorA" :intensity="1" :scale="10" :position="[-15, 4, -18]" />
|
||||
</Levioso>
|
||||
<TresGroup :rotation="[0, 0.5, 0]">
|
||||
<TresGroup ref="group">
|
||||
<Lightformer
|
||||
v-for="(i, x) in lightFormerPositions"
|
||||
:key="i"
|
||||
form="circle"
|
||||
:intensity="2"
|
||||
:rotation="[Math.PI / 2, 0, 0]"
|
||||
:position="[x, 4, i * 4]"
|
||||
:scale="[3, 1, 1]"
|
||||
/>
|
||||
</TresGroup>
|
||||
</TresGroup>
|
||||
<TresMesh :scale="[100, 100, 100]">
|
||||
<TresSphereGeometry :args="[1, 64, 64]" />
|
||||
<LayerMaterial :side="THREE.BackSide">
|
||||
<Color color="#444" :alpha="1.0" mode="normal" />
|
||||
<Depth
|
||||
:colorA="envSetup.colorB"
|
||||
colorB="black"
|
||||
:alpha="0.5"
|
||||
mode="normal"
|
||||
:near="0"
|
||||
:far="300"
|
||||
:origin="new THREE.Vector3(100, 100, 100)"
|
||||
/>
|
||||
</LayerMaterial>
|
||||
</TresMesh>
|
||||
</TresGroup>
|
||||
</Environment>
|
||||
</template>
|
||||
</Suspense>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch, ref } from 'vue'
|
||||
import * as THREE from 'three'
|
||||
import { useTresContext, useTexture, useRenderLoop } from '@tresjs/core'
|
||||
import { LayerMaterial, Color, Depth } from 'PLS/basic/components/forCientos/LayerMaterial'
|
||||
import { Environment, Lightformer } from 'PLS/basic'
|
||||
import { Levioso } from '@tresjs/cientos'
|
||||
|
||||
import { useBackgroundSetupStore } from 'PLS/tvtSceneCreator/stores/backgroundSetup'
|
||||
import { useEnvSetupStore } from 'PLS/tvtSceneCreator/stores/envSetup'
|
||||
|
||||
const lightFormerPositions = [2, 0, 2, 0, 2, 0, 2, 0]
|
||||
|
||||
const { scene } = useTresContext()
|
||||
const backgroundSetup = useBackgroundSetupStore()
|
||||
const envSetup = useEnvSetupStore()
|
||||
|
||||
const setupEnvBackground = async () => {
|
||||
// 格式化 环境
|
||||
if (envSetup.isLightFormer) {
|
||||
//
|
||||
} else {
|
||||
scene.value.environment = envSetup.envHDR.src
|
||||
}
|
||||
|
||||
// 格式化 背景
|
||||
if (backgroundSetup.useBackImg) {
|
||||
if (backgroundSetup.img.name === '') {
|
||||
scene.value.background = new THREE.Color(backgroundSetup.color)
|
||||
} else {
|
||||
const pTexture = await useTexture([backgroundSetup.img.src])
|
||||
scene.value.background = pTexture
|
||||
}
|
||||
} else {
|
||||
scene.value.background = scene.value.environment
|
||||
}
|
||||
scene.value.backgroundBlurriness = envSetup.blur
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
backgroundSetup.setupEnvBackground = setupEnvBackground
|
||||
|
||||
watch(
|
||||
() => backgroundSetup.color,
|
||||
() => {
|
||||
backgroundSetup.img = {
|
||||
name: '',
|
||||
src: '',
|
||||
}
|
||||
setupEnvBackground()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
watch(
|
||||
() => backgroundSetup.img,
|
||||
async (img) => {
|
||||
if (img.name) {
|
||||
setupEnvBackground()
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
watch(
|
||||
() => envSetup.envHDR,
|
||||
() => {
|
||||
setupEnvBackground()
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
watch(
|
||||
() => envSetup.isLightFormer,
|
||||
() => {
|
||||
setupEnvBackground()
|
||||
},
|
||||
)
|
||||
watch(
|
||||
() => backgroundSetup.useBackImg,
|
||||
() => {
|
||||
setupEnvBackground()
|
||||
},
|
||||
)
|
||||
watch(
|
||||
() => envSetup.blur,
|
||||
() => {
|
||||
setupEnvBackground()
|
||||
},
|
||||
)
|
||||
|
||||
const group = ref(null)
|
||||
const { onBeforeLoop } = useRenderLoop()
|
||||
onBeforeLoop(({ delta }) => {
|
||||
if (group.value) {
|
||||
// @ts-ignore
|
||||
;(group.value.position.z += delta * 10) > 20 && (group.value.position.z = -60)
|
||||
}
|
||||
})
|
||||
</script>
|
151
src/plugins/tvtSceneCreator/components/Tres/default/deMesh.vue
Normal file
@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<TresPerspectiveCamera :position="[20, 15, -20]" :fov="45" :near="0.1" :far="10000" :look-at="[0, 0, 0]" />
|
||||
<OrbitControls enableDamping makeDefault />
|
||||
|
||||
<TresGroup ref="tresGroupRef">
|
||||
<primitive :object="toRaw(mesh)" :meshListIndex="index" v-for="(mesh, index) in primitiveList" @click="pClick" />
|
||||
</TresGroup>
|
||||
<TransformControls
|
||||
@dragging="draggingEvent"
|
||||
v-if="transformRef && curMeshList.controlState !== 'sel' && curMeshList.controlState !== null && curMeshList.selectedMeshIndex !== null"
|
||||
:object="transformRef"
|
||||
:mode="curMeshList.controlState"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// @ts-nocheck
|
||||
import * as THREE from 'three'
|
||||
import { ref, onMounted, toRaw, watch } from 'vue'
|
||||
import { useTresContext, useSeek } from '@tresjs/core'
|
||||
import { OrbitControls, TransformControls, useGLTF } from '@tresjs/cientos'
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
|
||||
const curMeshList = useCurMeshListStore()
|
||||
|
||||
const transformRef = ref()
|
||||
const tresMeshRef = ref()
|
||||
|
||||
onMounted(() => {})
|
||||
|
||||
const getOneMesh = async (m) => {
|
||||
const mesh = m as any
|
||||
let onePrimitive = null as any
|
||||
if (mesh.type === 'AmbientLight') {
|
||||
onePrimitive = new THREE[mesh.type](mesh.color, mesh.intensity)
|
||||
onePrimitive.name = mesh.type
|
||||
} else if (mesh.type === 'DirectionalLight') {
|
||||
onePrimitive = new THREE[mesh.type](mesh.color, mesh.intensity)
|
||||
onePrimitive.position.set(...toRaw(mesh.position))
|
||||
onePrimitive.name = mesh.type
|
||||
} else if (mesh.type === 'Mesh') {
|
||||
const geometry = new THREE[mesh.geometry](...toRaw(mesh.args))
|
||||
const material = new THREE[mesh.material]()
|
||||
material.metalness = mesh.metalness
|
||||
material.roughness = mesh.roughness
|
||||
material.color = new THREE.Color(mesh.color)
|
||||
onePrimitive = new THREE[mesh.type](geometry, material)
|
||||
onePrimitive.name = mesh.name
|
||||
onePrimitive.position.set(...toRaw(mesh.position))
|
||||
onePrimitive.rotation.set(...toRaw(mesh.rotation))
|
||||
onePrimitive.scale.set(...toRaw(mesh.scale))
|
||||
} else {
|
||||
const { scene: modelScene } = await useGLTF(mesh.url, { draco: true, decoderPath: './draco/' })
|
||||
modelScene.name = mesh.name
|
||||
onePrimitive = modelScene
|
||||
onePrimitive.position.set(...toRaw(mesh.position))
|
||||
onePrimitive.rotation.set(...toRaw(mesh.rotation))
|
||||
onePrimitive.scale.set(...toRaw(mesh.scale))
|
||||
}
|
||||
onePrimitive.visible = mesh.visible
|
||||
return onePrimitive
|
||||
}
|
||||
const primitiveList = ref([])
|
||||
watch(
|
||||
() => curMeshList.mlist,
|
||||
async (mlist) => {
|
||||
const list = []
|
||||
for (const mesh of curMeshList.mlist) {
|
||||
list.push(await getOneMesh(mesh))
|
||||
}
|
||||
primitiveList.value = list
|
||||
console.log('primitiveList', list)
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
const pClick = (event) => {
|
||||
// event.stopPropagation()
|
||||
if (!curMeshList.controlState) {
|
||||
return
|
||||
}
|
||||
if (event.eventObject.meshListIndex) {
|
||||
curMeshList.selectedMeshIndex = event.eventObject.meshListIndex
|
||||
}
|
||||
}
|
||||
|
||||
const { scene } = useTresContext()
|
||||
const { seek } = useSeek()
|
||||
const tresGroupRef = ref()
|
||||
let directionalLightHelper = null as any
|
||||
watch(
|
||||
() => curMeshList.selectedMeshIndex,
|
||||
(index) => {
|
||||
if (directionalLightHelper) {
|
||||
directionalLightHelper.parent.remove(directionalLightHelper)
|
||||
directionalLightHelper.dispose()
|
||||
directionalLightHelper = null
|
||||
}
|
||||
scene.value.children.forEach((child) => {
|
||||
if (child.type === 'AmbientLight') {
|
||||
} else if (child.type === 'DirectionalLight') {
|
||||
if (child.meshListIndex === index) {
|
||||
directionalLightHelper = new THREE.DirectionalLightHelper(child, 10)
|
||||
scene.value.add(directionalLightHelper)
|
||||
}
|
||||
} else {
|
||||
if (child.material) {
|
||||
child.material.wireframe = child.meshListIndex === index
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (index !== null) {
|
||||
// const mesh = seek(tresGroupRef.value, 'meshListIndex', index) as any
|
||||
const mesh = seek(scene.value, 'meshListIndex', index) as any
|
||||
|
||||
if (mesh) {
|
||||
transformRef.value = toRaw(mesh)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
watch(
|
||||
() => curMeshList.controlState,
|
||||
(controlState) => {
|
||||
if (controlState) {
|
||||
//
|
||||
} else {
|
||||
curMeshList.selectedMeshIndex = null
|
||||
}
|
||||
},
|
||||
)
|
||||
watch(
|
||||
() => tresGroupRef.value,
|
||||
(value) => {
|
||||
// curMeshList.tresGroup = value
|
||||
curMeshList.tresGroup = scene.value
|
||||
|
||||
// curMeshList.addMesh({ name: 'AmbientLight', type: 'AmbientLight', intensity: 10 })
|
||||
// curMeshList.addMesh({ name: 'DirectionalLight', type: 'DirectionalLight', intensity: 5, position: [5, 3, 5] })
|
||||
// curMeshList.addMesh({ name: 'm1', position: [3, -3, 6], args: [6, 6, 6], metalness: 1, roughness: 0.14 })
|
||||
// curMeshList.addMesh({ name: 'm2', position: [0, 2, -4], material: 'MeshNormalMaterial', args: [2, 2, 2] })
|
||||
// curMeshList.addMesh({ name: 'm3', position: [0, 8, -4], material: 'MeshNormalMaterial', args: [2, 2, 2] })
|
||||
},
|
||||
)
|
||||
|
||||
const draggingEvent = (e: any) => {
|
||||
if (!e && window['TvTSCinForPane']) {
|
||||
window['TvTSCinForPane']()
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,52 @@
|
||||
<template></template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTresContext, useRenderLoop } from '@tresjs/core'
|
||||
// @ts-ignore
|
||||
import { ViewHelper } from 'three/addons/helpers/ViewHelper.js'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const { camera, renderer } = useTresContext()
|
||||
let panel = null as any
|
||||
const createDiv = () => {
|
||||
panel = document.createElement('div')
|
||||
panel.id = 'viewHelper'
|
||||
panel.style.position = 'absolute'
|
||||
// panel.style.right = '0px'
|
||||
panel.style.bottom = '0px'
|
||||
panel.style.height = '128px'
|
||||
panel.style.width = '128px'
|
||||
panel.style.pointerEvents = 'all'
|
||||
document.getElementById('app')?.appendChild(panel)
|
||||
}
|
||||
let viewHelper = null as any
|
||||
onMounted(() => {
|
||||
createDiv()
|
||||
viewHelper = new ViewHelper(camera.value, panel)
|
||||
panel.addEventListener('pointerup', (event: any) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
viewHelper.handleClick(event)
|
||||
})
|
||||
|
||||
panel.addEventListener('pointerdown', function (event: any) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
})
|
||||
|
||||
const { onBeforeLoop } = useRenderLoop()
|
||||
onBeforeLoop(({ delta }) => {
|
||||
if (!viewHelper)
|
||||
return
|
||||
|
||||
if (viewHelper.animating === true) {
|
||||
viewHelper.update(delta)
|
||||
}
|
||||
renderer.value.autoClear = false
|
||||
viewHelper?.render(renderer.value)
|
||||
renderer.value.autoClear = true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
25
src/plugins/tvtSceneCreator/components/Tres/index.vue
Normal file
@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<TresCanvas v-bind="tcConfig">
|
||||
<backgroundEnv />
|
||||
<defaultMesh />
|
||||
<viewHelper />
|
||||
</TresCanvas>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import * as THREE from "three"
|
||||
import backgroundEnv from './default/backgroundEnv.vue'
|
||||
import defaultMesh from './default/deMesh.vue'
|
||||
import viewHelper from './default/viewHelper.vue'
|
||||
|
||||
|
||||
const tcConfig = {
|
||||
clearColor: "#201919",
|
||||
windowSize: true,
|
||||
shadows: true,
|
||||
toneMapping: THREE.ACESFilmicToneMapping,
|
||||
toneMappingExposure: 0.8,
|
||||
}
|
||||
|
||||
</script>
|
60
src/plugins/tvtSceneCreator/components/UI/bottomContr.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="bt-con-div">
|
||||
<FRadioGroup v-model="curMeshList.controlState" size="small">
|
||||
<FRadioButton value="sel">
|
||||
<template #icon>
|
||||
<MinusCircleOutlined />
|
||||
</template>
|
||||
选择
|
||||
</FRadioButton>
|
||||
<FRadioButton value="translate">
|
||||
<template #icon>
|
||||
<DragOutlined />
|
||||
</template>
|
||||
移动
|
||||
</FRadioButton>
|
||||
<FRadioButton value="scale">
|
||||
<template #icon>
|
||||
<PlusCircleOutlined />
|
||||
</template>
|
||||
缩放
|
||||
</FRadioButton>
|
||||
<FRadioButton value="rotate">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
旋转
|
||||
</FRadioButton>
|
||||
</FRadioGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FRadioGroup, FRadioButton } from '@fesjs/fes-design'
|
||||
import { MinusCircleOutlined, DragOutlined, PlusCircleOutlined, ReloadOutlined } from '@fesjs/fes-design/icon'
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
|
||||
const curMeshList = useCurMeshListStore()
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.bt-con-div {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
width: 100%;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.bt-con-div {
|
||||
.fes-radio-group {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
width: 270px;
|
||||
pointer-events: all;
|
||||
|
||||
.fes-radio-button {
|
||||
background: #0f1222;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
80
src/plugins/tvtSceneCreator/components/UI/leftLayout.vue
Normal file
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div class="is-fixed" style="width: 280px; height: 700px; margin-top: 16px;pointer-events: all;">
|
||||
<FTabs type="card" v-model="otherConfig.activeModel">
|
||||
<FTabPane name="加入场景" value="modelList" displayDirective="show">
|
||||
<div class="tab-content">
|
||||
<modelList />
|
||||
</div>
|
||||
</FTabPane>
|
||||
<FTabPane name="现有物体" value="nowin" displayDirective="show">
|
||||
<div class="tab-content">
|
||||
<curList />
|
||||
</div>
|
||||
</FTabPane>
|
||||
<FTabPane name="独立效果" value="effect" displayDirective="show">
|
||||
<div class="tab-content" style="color: #fff;">
|
||||
导入TvT.js生态中封装好独立的效果组件敬请期待
|
||||
</div>
|
||||
</FTabPane>
|
||||
</FTabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FTabs, FTabPane } from '@fesjs/fes-design'
|
||||
import modelList from './small/modelList.vue'
|
||||
import curList from './small/curList.vue'
|
||||
import { useotherConfigStore } from 'PLS/tvtSceneCreator/stores/otherConfig'
|
||||
|
||||
const otherConfig = useotherConfigStore() as any
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.fes-scrollbar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar-track {
|
||||
background-color: #f1f1f1;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: #888;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
.fes-layout-aside.is-fixed.is-placement-left {
|
||||
top: 60px;
|
||||
}
|
||||
.fes-tabs-tab-pane {
|
||||
height: 100%;
|
||||
.tab-content {
|
||||
height: 100%;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
background: #0f1222;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.fes-tabs {
|
||||
background: #0f1222;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.fes-tabs-card .fes-tabs-tab-card.fes-tabs-tab-active{
|
||||
background: #0f1222;
|
||||
}
|
||||
.fes-tabs-card .fes-tabs-tab-card{
|
||||
background:#0e0e0e;
|
||||
}
|
||||
.fes-tabs-tab {
|
||||
color: #bcbcbc;
|
||||
}
|
||||
.fes-tabs-tab-active {
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
100
src/plugins/tvtSceneCreator/components/UI/rightEnvSetup.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class="right-env-setup">
|
||||
<FTabs v-model="reseletTab" type="card">
|
||||
<FTabPane name="场景设置" value="modelList" displayDirective="show">
|
||||
<div class="tab-content">
|
||||
<backgroundMap />
|
||||
<FDivider />
|
||||
<envMap />
|
||||
</div>
|
||||
</FTabPane>
|
||||
<FTabPane name="选中物体" value="selMesh" displayDirective="show">
|
||||
<div class="tab-content" style="color: #fff">
|
||||
<selMeshInfo />
|
||||
</div>
|
||||
</FTabPane>
|
||||
</FTabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { FDivider, FTabs, FTabPane } from '@fesjs/fes-design'
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
import backgroundMap from './small/backgroundMap.vue'
|
||||
import envMap from './small/envMap.vue'
|
||||
import selMeshInfo from './small/selMeshInfo.vue'
|
||||
|
||||
const curMeshList = useCurMeshListStore()
|
||||
|
||||
const reseletTab = ref('modelList')
|
||||
watch(
|
||||
() => curMeshList.selectedMeshIndex,
|
||||
(index) => {
|
||||
if (index !== null) {
|
||||
reseletTab.value = 'selMesh'
|
||||
}
|
||||
},
|
||||
)
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.right-env-setup {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
width: 260px;
|
||||
pointer-events: all;
|
||||
background-color: var(--f-font-color-base);
|
||||
color: var(--f-text-color-caption);
|
||||
right: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar-track {
|
||||
background-color: #f1f1f1;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: #888;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.fes-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
.fes-layout-aside.is-fixed.is-placement-left {
|
||||
top: 60px;
|
||||
}
|
||||
.fes-tabs-tab-pane {
|
||||
height: 100%;
|
||||
.tab-content {
|
||||
height: 100%;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.fes-tabs {
|
||||
background: #0f1222;
|
||||
color: var(--f-text-color-caption);
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.fes-tabs-card .fes-tabs-tab-card.fes-tabs-tab-active {
|
||||
background: #0f1222;
|
||||
}
|
||||
.fes-tabs-card .fes-tabs-tab-card {
|
||||
background: #0e0e0e;
|
||||
}
|
||||
.fes-tabs-tab {
|
||||
color: #bcbcbc;
|
||||
}
|
||||
.fes-tabs-tab-active {
|
||||
color: #ffffff;
|
||||
}
|
||||
.right-env-setup {
|
||||
.fes-tabs-tab-pane-wrapper {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<div class="backgroundMapDiv">
|
||||
<input type="file" id="fileBackground" accept="image/*" style="display: none" />
|
||||
<FText size="large" class="title">背景管理</FText>
|
||||
<div style="text-align: center; margin: 10px 0px">
|
||||
<FSwitch v-model="backgroundSetup.useBackImg">
|
||||
<template #active> 使用背景色 </template>
|
||||
<template #inactive> 使用环境贴图 </template>
|
||||
</FSwitch>
|
||||
</div>
|
||||
<div v-show="backgroundSetup.useBackImg">
|
||||
<div class="color-div"></div>
|
||||
<FGrid style="margin-top: 10px" :gutter="10">
|
||||
<FGridItem :span="6">
|
||||
<div class="col-title">默认颜色</div>
|
||||
</FGridItem>
|
||||
<FGridItem :span="18">
|
||||
<FRadioGroup v-model="selectedColor" @change="changeColor">
|
||||
<FRadioButton value="b"> 黑色 </FRadioButton>
|
||||
<FRadioButton value="w"> 白色 </FRadioButton>
|
||||
<FRadioButton value="g"> 灰色 </FRadioButton>
|
||||
</FRadioGroup>
|
||||
</FGridItem>
|
||||
</FGrid>
|
||||
<FGrid style="margin-top: 10px" :gutter="10">
|
||||
<FGridItem :span="6">
|
||||
<div class="col-title">选择图片</div>
|
||||
</FGridItem>
|
||||
<FGridItem :span="20">
|
||||
<FButton size="small" style="margin-top: 5px" @click="uploadImg()">
|
||||
<template #icon> <ProductOutlined /> </template>上传
|
||||
</FButton>
|
||||
</FGridItem>
|
||||
</FGrid>
|
||||
<FGrid style="margin-top: 10px" :gutter="10" wrap>
|
||||
<FGridItem v-for="ione in imgList" :span="8">
|
||||
<FImage
|
||||
style="width: 66px; height: 48px; margin-bottom: 8px; cursor: pointer"
|
||||
class="background-image"
|
||||
:class="{ 'sel-background-image': ione.name === backgroundSetup.img.name }"
|
||||
:src="ione.src"
|
||||
fit="contain"
|
||||
@click="imgclick(ione)"
|
||||
/>
|
||||
</FGridItem>
|
||||
</FGrid>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { FText, FRadioButton, FRadioGroup, FGrid, FGridItem, FButton, FImage, FSwitch, FMessage } from '@fesjs/fes-design'
|
||||
import { ProductOutlined } from '@fesjs/fes-design/icon'
|
||||
import { Pane } from 'tweakpane'
|
||||
import { useBackgroundSetupStore } from 'PLS/tvtSceneCreator/stores/backgroundSetup'
|
||||
|
||||
const backgroundSetup = useBackgroundSetupStore()
|
||||
const selectedColor = ref('')
|
||||
|
||||
let pane = null as any
|
||||
let fileInput = null as any
|
||||
|
||||
const changeColor = (color: string) => {
|
||||
if (color === 'b') {
|
||||
backgroundSetup.color = '#000'
|
||||
pane.children[0].refresh()
|
||||
}
|
||||
if (color === 'w') {
|
||||
backgroundSetup.color = '#fff'
|
||||
pane.children[0].refresh()
|
||||
}
|
||||
if (color === 'g') {
|
||||
backgroundSetup.color = '#888'
|
||||
pane.children[0].refresh()
|
||||
}
|
||||
}
|
||||
|
||||
const imgList = [
|
||||
{ name: 'upload', src: './plugins/tvtSceneCreator/image/backGround/upload.png' },
|
||||
{ name: 'b-blue', src: './plugins/tvtSceneCreator/image/backGround/b-blue.jpeg' },
|
||||
{ name: 'b-black', src: './plugins/tvtSceneCreator/image/backGround/b-black.jpeg' },
|
||||
{ name: 'b-green', src: './plugins/tvtSceneCreator/image/backGround/b-green.jpeg' },
|
||||
{ name: 'b-red', src: './plugins/tvtSceneCreator/image/backGround/b-red.jpeg' },
|
||||
{ name: 'b-cyan', src: './plugins/tvtSceneCreator/image/backGround/b-cyan.jpeg' },
|
||||
]
|
||||
const imgclick = (ione: any) => {
|
||||
if (ione.name === 'upload' && ione.src === './plugins/tvtSceneCreator/image/backGround/upload.png') {
|
||||
FMessage.error({
|
||||
content: `请先上传背景图片!`,
|
||||
colorful: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
backgroundSetup.img = { name: ione.name, src: ione.src }
|
||||
}
|
||||
const uploadImg = () => {
|
||||
fileInput.click()
|
||||
}
|
||||
onMounted(() => {
|
||||
const domcolor = document.querySelector('.backgroundMapDiv .color-div') as any
|
||||
pane = new Pane({ container: domcolor })
|
||||
pane.addBinding(backgroundSetup, 'color', { label: '纯色' })
|
||||
|
||||
fileInput = document.getElementById('fileBackground') as any
|
||||
fileInput.onchange = () => {
|
||||
const file = fileInput.files[0]
|
||||
if (file) {
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = () => {
|
||||
const imgSrc = reader.result as string
|
||||
imgList[0].src = imgSrc
|
||||
backgroundSetup.img = imgList[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.backgroundMapDiv {
|
||||
.title {
|
||||
color: var(--f-text-color-caption);
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
.color-div {
|
||||
margin: 6px 0px;
|
||||
}
|
||||
.fes-radio-button {
|
||||
background: #0f1222;
|
||||
}
|
||||
.col-title {
|
||||
font-size: 13px;
|
||||
line-height: 2.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.background-image {
|
||||
border: 1px solid #ffffff30;
|
||||
}
|
||||
.sel-background-image {
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
:root {
|
||||
--tp-base-background-color: #0f1222;
|
||||
--tp-label-foreground-color: #cfd0d3;
|
||||
}
|
||||
.tp-rotv {
|
||||
font-size: 13px !important;
|
||||
}
|
||||
</style>
|
84
src/plugins/tvtSceneCreator/components/UI/small/curList.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<FDraggable v-model="curMeshList.mlist" disabled>
|
||||
<template #default="{ item, index }">
|
||||
<div class="sort-item" :class="{ 'active': index === curMeshList.selectedMeshIndex }" @click="selListOne(index)">
|
||||
{{ item.name }}
|
||||
<template v-if="item.type!=='AmbientLight'&&item.type!=='DirectionalLight'">
|
||||
<{{item.type}}>
|
||||
</template>
|
||||
<CloseCircleFilled color="rgb(212 0 78)" class="del-i" @click="delItem(index)" />
|
||||
</div>
|
||||
</template>
|
||||
</FDraggable>
|
||||
<div style="color: white;" v-show="curMeshList.mlist.length === 0"> 暂无任何物体 </div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// <DragOutlined :size="18" :color="item.color" /> DragOutlined
|
||||
import { FDraggable, FModal } from '@fesjs/fes-design'
|
||||
import { CloseCircleFilled } from '@fesjs/fes-design/icon'
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
|
||||
const curMeshList = useCurMeshListStore() as any
|
||||
|
||||
// const getRandomBrightColor = () => {
|
||||
// const r = Math.floor(Math.random() * 128) + 128
|
||||
// const g = Math.floor(Math.random() * 128) + 128
|
||||
// const b = Math.floor(Math.random() * 128) + 128
|
||||
// const color = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`
|
||||
// return color
|
||||
// }
|
||||
|
||||
const delItem = (index: number) => {
|
||||
FModal.confirm({
|
||||
title: '删除选中项',
|
||||
content: `是否删除当前项:${curMeshList.mlist[index].name} ?`,
|
||||
okText: '确认删除',
|
||||
onOk() {
|
||||
if (curMeshList.selectedMeshIndex === index) {
|
||||
curMeshList.selectedMeshIndex = null
|
||||
}
|
||||
curMeshList.removeMesh(index)
|
||||
// curMeshList.selectedMeshIndex = curMeshList.mlist.length - 2
|
||||
},
|
||||
onCancel() {},
|
||||
})
|
||||
}
|
||||
|
||||
const selListOne = (index: number) => {
|
||||
if (!curMeshList.controlState) {
|
||||
curMeshList.controlState = 'sel'
|
||||
}
|
||||
curMeshList.selectedMeshIndex = index
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sort-item {
|
||||
line-height: 22px;
|
||||
background: #000;
|
||||
margin: 2px 0;
|
||||
padding-left: 23px;
|
||||
color: #cbcbcb;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
.fes-design-icon {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
}
|
||||
.del-i {
|
||||
right: 6px;
|
||||
top: 4px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss"></style>
|
185
src/plugins/tvtSceneCreator/components/UI/small/envMap.vue
Normal file
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="envMapDiv">
|
||||
<input type="file" id="fileEnv" accept=".hdr,.HDR" style="display: none" />
|
||||
<FText size="large" class="title">环境管理</FText>
|
||||
<div style="text-align: center; margin: 10px 0px">
|
||||
<FSwitch v-model="envSetup.isLightFormer">
|
||||
<template #active> lightFormer </template>
|
||||
<template #inactive> HDR 贴图 </template>
|
||||
</FSwitch>
|
||||
</div>
|
||||
<div v-show="!envSetup.isLightFormer">
|
||||
<FGrid style="margin-top: 10px" :gutter="10">
|
||||
<FGridItem :span="6">
|
||||
<div class="col-title">选择HDR</div>
|
||||
</FGridItem>
|
||||
<FGridItem :span="20">
|
||||
<FButton size="small" style="margin-top: 5px" @click="uploadImg()">
|
||||
<template #icon> <ProductOutlined /> </template>上传
|
||||
</FButton>
|
||||
</FGridItem>
|
||||
</FGrid>
|
||||
<FGrid style="margin-top: 10px" :gutter="10" wrap>
|
||||
<FGridItem v-for="ione in imgList" :span="8">
|
||||
<FImage
|
||||
style="width: 66px; height: 48px; margin-bottom: 8px; cursor: pointer"
|
||||
:src="ione.img"
|
||||
fit="contain"
|
||||
class="background-image"
|
||||
:class="{ 'sel-background-image': ione.name === envSetup.envHDR.name }"
|
||||
@click="imgclick(ione)"
|
||||
/>
|
||||
</FGridItem>
|
||||
</FGrid>
|
||||
</div>
|
||||
<div class="lightFormer-div"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { FText, FGrid, FGridItem, FButton, FImage, FSwitch, FMessage } from '@fesjs/fes-design'
|
||||
import { ProductOutlined } from '@fesjs/fes-design/icon'
|
||||
import { Pane } from 'tweakpane'
|
||||
import { useEnvSetupStore } from 'PLS/tvtSceneCreator/stores/envSetup'
|
||||
import { loadHDR } from 'PLS/skyBox/common/utils'
|
||||
|
||||
const envSetup = useEnvSetupStore()
|
||||
let pane = null as any
|
||||
let fileInput = null as any
|
||||
|
||||
const imgList = ref([
|
||||
{ name: 'upload', img: './plugins/tvtSceneCreator/image/backGround/upload.png', src: null },
|
||||
{
|
||||
name: 'desert',
|
||||
img: './plugins/tvtSceneCreator/image/envHDR/desert.jpeg',
|
||||
src: await loadHDR('https://opensource-1314935952.cos.ap-nanjing.myqcloud.com/images/skyBox/desert_1k.hdr'),
|
||||
},
|
||||
{
|
||||
name: 'belfast_sunset_puresky_1k',
|
||||
img: './plugins/tvtSceneCreator/image/envHDR/belfast_sunset_puresky_1k.jpeg',
|
||||
src: await loadHDR('./plugins/tvtSceneCreator/image/envHDR/belfast_sunset_puresky_1k.hdr'),
|
||||
},
|
||||
{
|
||||
name: 'metro_noord_1k',
|
||||
img: './plugins/tvtSceneCreator/image/envHDR/metro_noord_1k.jpeg',
|
||||
src: await loadHDR('./plugins/tvtSceneCreator/image/envHDR/metro_noord_1k.hdr'),
|
||||
},
|
||||
{
|
||||
name: 'pretville_cinema_1k',
|
||||
img: './plugins/tvtSceneCreator/image/envHDR/pretville_cinema_1k.jpeg',
|
||||
src: await loadHDR('./plugins/tvtSceneCreator/image/envHDR/pretville_cinema_1k.hdr'),
|
||||
},
|
||||
{
|
||||
name: 'shanghai_bund_1k',
|
||||
img: './plugins/tvtSceneCreator/image/envHDR/shanghai_bund_1k.jpeg',
|
||||
src: await loadHDR('./plugins/tvtSceneCreator/image/envHDR/shanghai_bund_1k.hdr'),
|
||||
},
|
||||
])
|
||||
const uploadImg = () => {
|
||||
fileInput.click()
|
||||
}
|
||||
const imgclick = async (ione: any) => {
|
||||
if (ione.name === 'upload' && !ione.src) {
|
||||
FMessage.error({
|
||||
content: `请先上传HDR图片!`,
|
||||
colorful: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
envSetup.envHDR.name = ione.name
|
||||
envSetup.envHDR.src = ione.src
|
||||
}
|
||||
|
||||
const setEnvHDR = (name: string) => {
|
||||
imgList.value.forEach((item) => {
|
||||
if (item.name === name) {
|
||||
envSetup.envHDR.name = name
|
||||
envSetup.envHDR.src = item.src
|
||||
}
|
||||
})
|
||||
}
|
||||
envSetup.setEnvHDR = setEnvHDR
|
||||
let fcc = null as any
|
||||
onMounted(() => {
|
||||
const domcolor = document.querySelector('.envMapDiv .lightFormer-div') as any
|
||||
pane = new Pane({ container: domcolor })
|
||||
pane.addBinding(envSetup, 'blur', { label: '背景模糊', min: 0, max: 1.0, step: 0.01 })
|
||||
|
||||
fcc = pane.addFolder({ title: '属性' })
|
||||
fcc.addBinding(envSetup, 'colorA', { label: '颜色1' })
|
||||
fcc.addBinding(envSetup, 'colorB', { label: '颜色2' })
|
||||
fcc.addBinding(envSetup, 'pos', { label: '位置' })
|
||||
fcc.addBinding(envSetup, 'rotate', { label: '旋转' })
|
||||
fcc.addBinding(envSetup, 'scale', { label: '缩放', min: 0.1, max: 2.0, step: 0.01 })
|
||||
fcc.hidden = true
|
||||
|
||||
fileInput = document.getElementById('fileEnv') as any
|
||||
fileInput.onchange = () => {
|
||||
const file = fileInput.files[0]
|
||||
if (file) {
|
||||
const reader = new FileReader()
|
||||
reader.readAsArrayBuffer(file)
|
||||
reader.onload = async (e) => {
|
||||
if (e.target) {
|
||||
const arrayBuffer = e.target.result as ArrayBuffer
|
||||
const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
|
||||
const texture = await loadHDR(url)
|
||||
// texture.mapping = THREE.EquirectangularReflectionMapping
|
||||
// texture.minFilter = THREE.LinearFilter
|
||||
// texture.magFilter = THREE.LinearFilter
|
||||
imgList.value[0].img = './plugins/tvtSceneCreator/image/envHDR/finishHDR.png'
|
||||
imgList.value[0].src = texture
|
||||
envSetup.envHDR.name = 'upload'
|
||||
envSetup.envHDR.src = texture
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => envSetup.isLightFormer,
|
||||
(v) => {
|
||||
fcc.hidden = !v
|
||||
},
|
||||
)
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.envMapDiv {
|
||||
margin-top: -10px;
|
||||
.title {
|
||||
color: var(--f-text-color-caption);
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
.color-div {
|
||||
margin: 6px 0px;
|
||||
}
|
||||
.fes-radio-button {
|
||||
background: #0f1222;
|
||||
}
|
||||
.col-title {
|
||||
font-size: 13px;
|
||||
line-height: 2.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.background-image {
|
||||
border: 1px solid #ffffff30;
|
||||
}
|
||||
.sel-background-image {
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
:root {
|
||||
--tp-base-background-color: #0f1222;
|
||||
--tp-label-foreground-color: #cfd0d3;
|
||||
}
|
||||
.tp-rotv {
|
||||
font-size: 13px !important;
|
||||
}
|
||||
</style>
|
145
src/plugins/tvtSceneCreator/components/UI/small/modelList.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div class="fit-demo">
|
||||
<FCollapse v-model="activeNames">
|
||||
<FCollapseItem title="模型列表" name="1">
|
||||
<div class="list-div">
|
||||
<div v-for="(item, index) in modelFileList" :key="index" class="block" @click="addMesh(item)">
|
||||
<FEllipsis class="demonstration" :content="item.name" :tooltip="{ popperClass: 'a', showAfter: 500 }" style="max-width: 100px" />
|
||||
<FImage style="width: 100px; height: 100px" :src="item.img" fit="contain" />
|
||||
</div>
|
||||
</div>
|
||||
</FCollapseItem>
|
||||
<FCollapseItem title="常用灯光" name="2">
|
||||
<div class="one-light" @click="addMesh('ambientLight')"><PlusCircleFilled :size="13" /> 环境光</div>
|
||||
<div class="one-light" @click="addMesh('directionalLight')"><PlusCircleFilled :size="13" /> 平行光</div>
|
||||
</FCollapseItem>
|
||||
<FCollapseItem title="常用物体" name="3">
|
||||
<div class="one-light" @click="addMesh('Sphere')"><PlusCircleFilled :size="13" /> 圆球</div>
|
||||
<div class="one-light" @click="addMesh('Box')"><PlusCircleFilled :size="13" /> 立方体</div>
|
||||
</FCollapseItem>
|
||||
</FCollapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { FImage, FEllipsis, FCollapse, FCollapseItem, FMessage } from '@fesjs/fes-design'
|
||||
import { PlusCircleFilled } from '@fesjs/fes-design/icon'
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
import { useotherConfigStore } from 'PLS/tvtSceneCreator/stores/otherConfig'
|
||||
import { modelFileList } from 'PLS/tvtSceneCreator/modelList.config.js'
|
||||
|
||||
const otherConfig = useotherConfigStore() as any
|
||||
const curMeshList = useCurMeshListStore() as any
|
||||
|
||||
const addMesh = (type: any) => {
|
||||
if (type === 'ambientLight') {
|
||||
if (curMeshList.hasAmbientLight()) {
|
||||
FMessage.error({
|
||||
content: `场景内已存在环境光,不能再添加!`,
|
||||
colorful: false,
|
||||
})
|
||||
return
|
||||
} else {
|
||||
curMeshList.addMesh({ name: 'AmbientLight', type: 'AmbientLight', intensity: 10 })
|
||||
}
|
||||
} else if (type === 'directionalLight') {
|
||||
curMeshList.addMesh({ name: 'DirectionalLight', type: 'DirectionalLight', intensity: 5, position: [5, 3, 5] })
|
||||
} else if (type === 'Box') {
|
||||
curMeshList.addMesh({ name: 'Box-add', type: 'Mesh', position: [0, 0, 0], args: [10, 10, 10], metalness: 1, roughness: 0.14 })
|
||||
} else if (type === 'Sphere') {
|
||||
curMeshList.addMesh({
|
||||
name: 'Sphere-add',
|
||||
type: 'Mesh',
|
||||
position: [0, 0, 0],
|
||||
args: [2, 32, 16],
|
||||
geometry: 'SphereGeometry',
|
||||
material: 'MeshStandardMaterial',
|
||||
})
|
||||
} else {
|
||||
curMeshList.addMesh({
|
||||
name: type.name,
|
||||
type: type.type,
|
||||
position: [0, 0, 0],
|
||||
url: type.url,
|
||||
})
|
||||
}
|
||||
curMeshList.selectedMeshIndex = null
|
||||
otherConfig.activeModel = 'nowin'
|
||||
}
|
||||
const activeNames = ref(['1'])
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.fit-demo {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 600px;
|
||||
.list-div {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.block {
|
||||
width: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
padding-right: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.one-light {
|
||||
text-align: left;
|
||||
padding: 10px 0px 10px 40px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
line-height: 14px;
|
||||
position: relative;
|
||||
.fes-design-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.fit-demo::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.fit-demo::-webkit-scrollbar-track {
|
||||
background-color: #f1f1f1;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.fit-demo::-webkit-scrollbar-thumb {
|
||||
background-color: #888;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.fit-demo::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.fit-demo {
|
||||
.block {
|
||||
.demonstration {
|
||||
font-size: 12px;
|
||||
color: #eee;
|
||||
line-height: 28px;
|
||||
margin-top: -10px;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
}
|
||||
.fes-collapse-item__header {
|
||||
background: #0f1222;
|
||||
color: var(--f-text-color-caption);
|
||||
}
|
||||
.fes-collapse-item__wrap.is-embedded {
|
||||
background: #0f1222;
|
||||
}
|
||||
.fes-collapse-item__content {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
124
src/plugins/tvtSceneCreator/components/UI/small/selMeshInfo.vue
Normal file
@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="selMeshInfo-div" v-show="curMeshList.selectedMeshIndex !== null">
|
||||
<FText size="large" class="title">详情信息</FText>
|
||||
<div class="info-div" />
|
||||
</div>
|
||||
<div v-show="curMeshList.selectedMeshIndex === null">暂未选择物体</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, watch, toRaw } from 'vue'
|
||||
import { useSeek } from '@tresjs/core'
|
||||
import { FText } from '@fesjs/fes-design'
|
||||
import { Pane } from 'tweakpane'
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
|
||||
const curMeshList = useCurMeshListStore()
|
||||
|
||||
const PARAMS = {
|
||||
meshType: 'Mesh',
|
||||
meshName: '自行车',
|
||||
uuid: '1234567890',
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
rotation: { x: 0, y: 0, z: 0 },
|
||||
scale: { x: 1, y: 1, z: 1 },
|
||||
|
||||
renderOrder: 0,
|
||||
visible: true,
|
||||
castShadow: true,
|
||||
receiveShadow: true,
|
||||
}
|
||||
let pane = null as any
|
||||
const { seek } = useSeek()
|
||||
let selMesh = null as any
|
||||
watch(
|
||||
() => curMeshList.selectedMeshIndex,
|
||||
(index) => {
|
||||
bingPARAMS()
|
||||
},
|
||||
)
|
||||
const bingPARAMS = () => {
|
||||
const index = curMeshList.selectedMeshIndex
|
||||
if (index !== null) {
|
||||
const mesh = seek(curMeshList.tresGroup as any, 'meshListIndex', index) as any
|
||||
if (mesh) {
|
||||
selMesh = toRaw(mesh)
|
||||
PARAMS.meshType = selMesh.type
|
||||
PARAMS.meshName = selMesh.name
|
||||
PARAMS.uuid = selMesh.uuid
|
||||
|
||||
PARAMS.position = selMesh.position
|
||||
PARAMS.rotation = selMesh.rotation
|
||||
PARAMS.scale = selMesh.scale
|
||||
|
||||
PARAMS.renderOrder = selMesh.renderOrder
|
||||
PARAMS.visible = selMesh.visible
|
||||
PARAMS.castShadow = selMesh.castShadow
|
||||
PARAMS.receiveShadow = selMesh.receiveShadow
|
||||
|
||||
pane.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
window['TvTSCinForPane'] = bingPARAMS
|
||||
onMounted(() => {
|
||||
const domcolor = document.querySelector('.selMeshInfo-div .info-div') as any
|
||||
pane = new Pane({ container: domcolor })
|
||||
pane.addBinding(PARAMS, 'meshType', { label: '物体类型', disabled: true })
|
||||
pane.addBinding(PARAMS, 'meshName', { label: '物体名称', disabled: true })
|
||||
pane.addBinding(PARAMS, 'uuid', { label: '识别码', disabled: true })
|
||||
|
||||
pane.addBinding(PARAMS, 'position', { label: '位置' })
|
||||
pane.addBinding(PARAMS, 'rotation', { label: '旋转' })
|
||||
pane.addBinding(PARAMS, 'scale', { label: '缩放' })
|
||||
|
||||
pane.addBinding(PARAMS, 'renderOrder', { label: '渲染顺序', step: 1, min: 0 })
|
||||
pane.addBinding(PARAMS, 'visible', { label: '是否可见' })
|
||||
pane.addBinding(PARAMS, 'castShadow', { label: '产生阴影' })
|
||||
pane.addBinding(PARAMS, 'receiveShadow', { label: '接受阴影' })
|
||||
|
||||
pane.on('change', (ev: any) => {
|
||||
if (ev.target.key === 'visible') {
|
||||
selMesh.visible = ev.value
|
||||
}
|
||||
if (ev.target.key === 'renderOrder') {
|
||||
selMesh.renderOrder = ev.value
|
||||
}
|
||||
if (ev.target.key === 'castShadow') {
|
||||
selMesh.castShadow = ev.value
|
||||
}
|
||||
if (ev.target.key === 'receiveShadow') {
|
||||
selMesh.receiveShadow = ev.value
|
||||
}
|
||||
const index = curMeshList.selectedMeshIndex
|
||||
if (index !== null) {
|
||||
const mesh = toRaw(seek(curMeshList.tresGroup as any, 'meshListIndex', index)) as any
|
||||
const mObject = toRaw(curMeshList.mlist[index]) as any
|
||||
if (mesh && ev.target.key !== 'uuid') {
|
||||
console.log(ev.target.key, index, mesh, mObject)
|
||||
if (mesh[ev.target.key] && mObject[ev.target.key]) {
|
||||
if (ev.target.key === 'position' || ev.target.key === 'rotation' || ev.target.key === 'scale') {
|
||||
mObject[ev.target.key][0] = mesh[ev.target.key].x
|
||||
mObject[ev.target.key][1] = mesh[ev.target.key].y
|
||||
mObject[ev.target.key][2] = mesh[ev.target.key].z
|
||||
} else {
|
||||
mObject[ev.target.key] = mesh[ev.target.key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.selMeshInfo-div {
|
||||
.title {
|
||||
color: var(--f-text-color-caption);
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss"></style>
|
172
src/plugins/tvtSceneCreator/components/UI/topMenu.vue
Normal file
@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<f-menu inverted @select="handleSelect">
|
||||
<f-sub-menu value="1">
|
||||
<template #icon>
|
||||
<FolderOutlined />
|
||||
</template>
|
||||
<template #label>文件</template>
|
||||
<f-menu-item value="1.1">
|
||||
<template #label>新建 - 场景</template>
|
||||
</f-menu-item>
|
||||
<f-menu-item value="1.2">
|
||||
<template #label>导入 - 场景配置</template>
|
||||
</f-menu-item>
|
||||
<f-menu-item value="1.3">
|
||||
<template #label>导出 - 场景配置</template>
|
||||
</f-menu-item>
|
||||
<f-menu-item value="1.4">
|
||||
<template #label>生成 - 项目插件包</template>
|
||||
</f-menu-item>
|
||||
</f-sub-menu>
|
||||
<!-- <f-sub-menu value="2">
|
||||
<template #icon>
|
||||
<SettingOutlined />
|
||||
</template>
|
||||
<template #label>场景设置</template>
|
||||
<f-menu-item value="2.1" label="环境设置" />
|
||||
<f-menu-item value="2.2" label="全屏" />
|
||||
</f-sub-menu>
|
||||
<f-sub-menu value="3">
|
||||
<template #icon>
|
||||
<ShareOutlined />
|
||||
</template>
|
||||
<template #label>助手</template>
|
||||
<f-menu-item value="3.1" label="网格助手" />
|
||||
<f-menu-item value="3.2" label="灯光助手" />
|
||||
<f-menu-item value="3.3" label="场景属性" />
|
||||
<f-menu-item value="3.4" label="陀螺仪" />
|
||||
</f-sub-menu>
|
||||
<f-menu-item value="4" label="当前预览">
|
||||
<template #icon>
|
||||
<EyeOutlined />
|
||||
</template>
|
||||
</f-menu-item> -->
|
||||
<f-sub-menu value="5">
|
||||
<template #icon>
|
||||
<ShareOutlined />
|
||||
</template>
|
||||
<template #label>关于</template>
|
||||
<f-menu-item value="5.1" label="功能介绍" />
|
||||
<f-menu-item value="5.2" label="视频说明" />
|
||||
<f-menu-item value="5.3" label="免费源码包" />
|
||||
</f-sub-menu>
|
||||
</f-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FMenu, FSubMenu, FMenuItem, FMessage } from '@fesjs/fes-design'
|
||||
import { FolderOutlined, ShareOutlined } from '@fesjs/fes-design/icon' // SettingOutlined EyeOutlined
|
||||
import { useCurMeshListStore } from 'PLS/tvtSceneCreator/stores/curMeshList'
|
||||
import { useBackgroundSetupStore } from 'PLS/tvtSceneCreator/stores/backgroundSetup'
|
||||
import { useEnvSetupStore } from 'PLS/tvtSceneCreator/stores/envSetup'
|
||||
|
||||
|
||||
const envSetup = useEnvSetupStore()
|
||||
const backgroundSetup = useBackgroundSetupStore()
|
||||
const curMeshList = useCurMeshListStore()
|
||||
|
||||
const exportSceneConfig = () => {
|
||||
const configAll = {
|
||||
mlist: curMeshList.mlist,
|
||||
envSetup: envSetup,
|
||||
backgroundSetup: backgroundSetup,
|
||||
}
|
||||
debugger
|
||||
const fileContent = JSON.stringify(configAll, null, 2)
|
||||
const blob = new Blob([fileContent], { type: 'application/javascript' })
|
||||
const a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = 'tvtSceneCreator.config.js'
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
}
|
||||
|
||||
const inputSceneConfig = () => {
|
||||
if (curMeshList.mlist.length > 0) {
|
||||
FMessage.error({
|
||||
content: `当前场景存在物体,请新建空场景再导入配置!`,
|
||||
colorful: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = '.js'
|
||||
input.onchange = async (event: any) => {
|
||||
const file = event.target.files[0]
|
||||
if (file) {
|
||||
const text = await file.text()
|
||||
try {
|
||||
const config = JSON.parse(text) as any
|
||||
curMeshList.mlist = config.mlist
|
||||
|
||||
envSetup.isLightFormer = config.envSetup.isLightFormer
|
||||
envSetup.colorA = config.envSetup.colorA
|
||||
envSetup.colorB = config.envSetup.colorB
|
||||
envSetup.blur = config.envSetup.blur
|
||||
envSetup.pos = config.envSetup.pos
|
||||
envSetup.rotate = config.envSetup.rotate
|
||||
envSetup.scale = config.envSetup.scale
|
||||
if (config.envSetup.envHDR.name !== 'upload') {
|
||||
envSetup.setEnvHDR(config.envSetup.envHDR.name)
|
||||
}
|
||||
|
||||
backgroundSetup.color = config.backgroundSetup.color
|
||||
backgroundSetup.img = config.backgroundSetup.img
|
||||
backgroundSetup.useBackImg = config.backgroundSetup.useBackImg
|
||||
|
||||
FMessage.info({
|
||||
content: `配置导入成功!`,
|
||||
colorful: true,
|
||||
})
|
||||
} catch (error: any) {
|
||||
FMessage.error({
|
||||
content: `读取文件时发生错误: ${error.message}`,
|
||||
colorful: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
input.click()
|
||||
}
|
||||
|
||||
const handleSelect = ({ value }: { value: string }) => {
|
||||
if (value === '5.1') {
|
||||
window.open('https://www.icegl.cn/tvtstore/tvtSceneCreator')
|
||||
}
|
||||
if (value === '5.3') {
|
||||
window.open('https://www.icegl.cn/tvtstore/tvtSceneCreator')
|
||||
}
|
||||
if (value === '5.2' || value === '1.4') {
|
||||
FMessage.info({
|
||||
content: `功能更新中,敬请期待!`,
|
||||
colorful: true,
|
||||
})
|
||||
}
|
||||
if (value === '1.1') {
|
||||
curMeshList.clearMesh()
|
||||
FMessage.info({
|
||||
content: `场景已清空!`,
|
||||
colorful: true,
|
||||
})
|
||||
}
|
||||
if (value === '1.3') {
|
||||
exportSceneConfig()
|
||||
FMessage.info({
|
||||
content: `配置导出成功!`,
|
||||
colorful: true,
|
||||
})
|
||||
}
|
||||
if (value === '1.2') {
|
||||
inputSceneConfig()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.fes-sub-menu {
|
||||
min-width: 120px;
|
||||
pointer-events: all;
|
||||
}
|
||||
</style>
|
22
src/plugins/tvtSceneCreator/config.js
Normal file
@ -0,0 +1,22 @@
|
||||
export default {
|
||||
"name": "tvtSceneCreator",
|
||||
"title": "TvT.js场景生成器",
|
||||
"intro": `根据模型列表,设置光源、背景、环境等,生成场景, 导入导出配置,生成插件包,持续更新中...
|
||||
整体文档教程和免费插件下载详见:<a style="color: #5384ff;" href="https://www.icegl.cn/tvtstore/tvtSceneCreator" target="_blank">TvT.js场景生成器</a>`,
|
||||
"version": "1.0.0",
|
||||
"author": '地虎降天龙',
|
||||
"website": 'https://gitee.com/hawk86104',
|
||||
"state": "active",
|
||||
"creatTime": "2024-08-20",
|
||||
"updateTime": "2024-08-20",
|
||||
"require": [],
|
||||
"tvtstore": 'FREE',
|
||||
"preview": [{
|
||||
"src": "/plugins/tvtSceneCreator/preview/index.png",
|
||||
"type": "img",
|
||||
"name": "index",
|
||||
"title": "场景生成器预览",
|
||||
disableFPSGraph: false,
|
||||
disableSrcBtn: true
|
||||
}, ]
|
||||
}
|
9
src/plugins/tvtSceneCreator/modelList.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
export const modelFileList = [
|
||||
{ name: '笔记本', url: './plugins/basic/htmls/model/model.gltf', type: 'gltf', img: './plugins/basic/htmls/preview/websiteReflector.png' },
|
||||
{
|
||||
name: '飞机',
|
||||
url: 'https://opensource-1314935952.cos.ap-nanjing.myqcloud.com/model/industry4/plane/scene.gltf',
|
||||
type: 'gltf',
|
||||
img: './plugins/UIdemo/preview/sizeMark.png',
|
||||
},
|
||||
]
|
76
src/plugins/tvtSceneCreator/pages/index.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<threeDcom />
|
||||
<FConfigProvider :themeOverrides="themeOverrides">
|
||||
<div
|
||||
id="UIDIV"
|
||||
style="
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE10+/Edge */
|
||||
user-select: none; /* Standard syntax */
|
||||
"
|
||||
>
|
||||
<topMenu />
|
||||
<leftLayout />
|
||||
<rightEnvSetup />
|
||||
<bottomContr />
|
||||
</div>
|
||||
</FConfigProvider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FConfigProvider } from '@fesjs/fes-design'
|
||||
|
||||
import topMenu from '../components/UI/topMenu.vue'
|
||||
import leftLayout from '../components/UI/leftLayout.vue'
|
||||
import rightEnvSetup from '../components/UI/rightEnvSetup.vue'
|
||||
import bottomContr from '../components/UI/bottomContr.vue'
|
||||
import threeDcom from '../components/Tres/index.vue'
|
||||
|
||||
const themeOverrides = {
|
||||
common: {
|
||||
primaryColor: '#8f98ff',
|
||||
|
||||
successColor: '#00cb91',
|
||||
dangerColor: '#ff4d4f',
|
||||
warningColor: '#f29360',
|
||||
tipColor: '#8f98ff',
|
||||
|
||||
white: '#fff',
|
||||
black: '#000',
|
||||
|
||||
bodyBgColor: '#fff',
|
||||
|
||||
fontColorBase: '#0f1222',
|
||||
fontSizeBase: '14px',
|
||||
|
||||
borderRadiusBase: '4px',
|
||||
borderRadiusSm: '2px',
|
||||
borderWidthBase: '1px',
|
||||
borderStyleBase: 'solid',
|
||||
|
||||
borderColorBase: '#cfd0d3',
|
||||
|
||||
shadowColor: 'rgba(18, 18, 18, 0.1)',
|
||||
shadowColorSm: 'rgba(18, 18, 18, 0.2)',
|
||||
shadowRadius: '12px',
|
||||
shadowRadiusSm: '4px',
|
||||
|
||||
maskColor: 'rgba(18, 18, 18, 0.45)',
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
:root {
|
||||
.fpsStats {
|
||||
top: 7px;
|
||||
right: 8px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
14
src/plugins/tvtSceneCreator/stores/backgroundSetup.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useBackgroundSetupStore = defineStore('backgroundSetup', () => {
|
||||
const color = ref('#333333')
|
||||
const img = ref({
|
||||
name: '',
|
||||
src: '',
|
||||
})
|
||||
const useBackImg = ref(true)
|
||||
const setupEnvBackground = ref(null)
|
||||
|
||||
return { color, img, useBackImg, setupEnvBackground }
|
||||
})
|
49
src/plugins/tvtSceneCreator/stores/curMeshList.js
Normal file
@ -0,0 +1,49 @@
|
||||
/* eslint-disable no-undefined */
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useCurMeshListStore = defineStore('curMeshList', () => {
|
||||
const controlState = ref('sel') // rotate scale translate
|
||||
|
||||
const mlist = ref([])
|
||||
|
||||
const addMesh = (mesh) => {
|
||||
const one = {
|
||||
name: mesh.name !== undefined ? mesh.name : 'deMesh',
|
||||
type: mesh.type ? mesh.type : 'Mesh',
|
||||
position: mesh.position ? mesh.position : [0, 0, 0],
|
||||
rotation: mesh.rotation ? mesh.rotation : [0, 0, 0],
|
||||
scale: mesh.scale ? mesh.scale : [1, 1, 1],
|
||||
visible: mesh.visible !== undefined ? mesh.visible : true,
|
||||
renderOrder: mesh.renderOrder ? mesh.renderOrder : 0,
|
||||
receiveShadow: mesh.receiveShadow !== undefined ? mesh.receiveShadow : false,
|
||||
castShadow: mesh.castShadow !== undefined ? mesh.castShadow : false,
|
||||
geometry: mesh.geometry ? mesh.geometry : 'BoxGeometry',
|
||||
args: mesh.args ? mesh.args : [1, 1, 1],
|
||||
material: mesh.material ? mesh.material : 'MeshStandardMaterial',
|
||||
metalness: mesh.metalness ? mesh.metalness : 0,
|
||||
roughness: mesh.roughness ? mesh.roughness : 0.5,
|
||||
color: mesh.color ? mesh.color : '#ffffff',
|
||||
intensity: mesh.intensity ? mesh.intensity : 1,
|
||||
url: mesh.url ? mesh.url : '',
|
||||
}
|
||||
mlist.value.push(one)
|
||||
}
|
||||
|
||||
const removeMesh = (index) => {
|
||||
mlist.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const hasAmbientLight = () => mlist.value.some((mesh) => mesh.type === 'AmbientLight')
|
||||
|
||||
const selectedMeshIndex = ref(null)
|
||||
|
||||
const clearMesh = () => {
|
||||
mlist.value = []
|
||||
selectedMeshIndex.value = null
|
||||
}
|
||||
|
||||
const tresGroup = ref(null)
|
||||
|
||||
return { controlState, mlist, addMesh, removeMesh, selectedMeshIndex, tresGroup, hasAmbientLight,clearMesh }
|
||||
})
|
21
src/plugins/tvtSceneCreator/stores/envSetup.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useEnvSetupStore = defineStore('envSetup', () => {
|
||||
const isLightFormer = ref(false)
|
||||
const colorA = ref('#ff0000')
|
||||
const colorB = ref('#0000ff')
|
||||
const blur = ref(1)
|
||||
const pos = ref({ x: 0, y: 0, z: 0 })
|
||||
const rotate = ref({ x: 0, y: 0, z: 0 })
|
||||
const scale = ref({ x: 1, y: 1, z: 1 })
|
||||
|
||||
const envHDR = ref({
|
||||
name: '',
|
||||
src: null,
|
||||
})
|
||||
|
||||
const setEnvHDR = ref()
|
||||
|
||||
return { isLightFormer, colorA, colorB, blur, pos, rotate, scale, envHDR, setEnvHDR }
|
||||
})
|
8
src/plugins/tvtSceneCreator/stores/otherConfig.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useotherConfigStore = defineStore('otherConfig', () => {
|
||||
const activeModel = ref('modelList')
|
||||
|
||||
return { activeModel }
|
||||
})
|