dev #90

Merged
ksenia_mikhailova merged 20 commits from dev into main 2025-03-20 14:15:19 +03:00
5 changed files with 195 additions and 147 deletions
Showing only changes of commit fea664c209 - Show all commits

View File

@ -27,21 +27,18 @@ const cameraStat = reactive({
</div>
</template>
<Loader />
<TresCanvas clear-color="#e2e8f0">
<Scene :canvasProps="{ clearColor: '#e2e8f0' }">
<TresPerspectiveCamera v-bind="cameraStat" ref="camera" />
<OrbitControls v-bind="controlsState" make-default />
<Suspense>
<ModelSmoothCamera />
</Suspense>
<Suspense>
<ModelEnv />
</Suspense>
<TresGroup>
<Suspense>
<ModelParametric />
</Suspense>
</TresGroup>
</TresCanvas>
</Scene>
</ClientOnly>
</div>
</template>

View File

@ -17,22 +17,6 @@ const explosion_state = use_explosion_state()
const toggleExpState = () => {
explosion_state.value = !explosion_state.value
}
const back_light = ref()
const secondary_light = ref()
const loadAll = async () => {
const { scene: back } = await useGLTF('/models_light/back_exp.glb')
const { scene: secondary } = await useGLTF('/models_light/secondary_exp.glb')
const k = 0.03
back_light.value = back.children[0]
back_light.value.intensity = back_light.value.intensity * k
back_light.value.shadow.bias = -0.02
secondary_light.value = secondary.children[0]
secondary_light.value.intensity = secondary_light.value.intensity * k
secondary_light.value.shadow.bias = -0.01
}
const changeDistance = (v = 1) => {
if (camera.value && controls.value) {
@ -41,9 +25,6 @@ const changeDistance = (v = 1) => {
camera.value.position.normalize().multiplyScalar(r)
}
}
onMounted(() => {
loadAll()
})
</script>
<template>
<div class="h-96 relative">
@ -53,14 +34,11 @@ onMounted(() => {
Загрузка 3D модели
</div>
</template>
<TresCanvas height="600">
<Scene :canvasProps="{ height: '600' }">
<TresPerspectiveCamera :position="[-7, 2, 4]" ref="camera" />
<OrbitControls v-bind="controlsState" ref="controls" make-default />
<ModelEnv />
<Suspense>
<ModelDiagram />
</Suspense>
</TresCanvas>
<ModelDiagram />
</Scene>
</ClientOnly>
<div class="canvas-icons">
<a href="#" @click.prevent="toggleExpState">

View File

@ -22,131 +22,149 @@ const { seek, seekAll } = useSeek()
const globalFenceType = useGlobalFenceType()
const topper_models = {
baseToppers: {} as { [key: toppersIds]: Object3D },
aristoToppers: {} as { [key: toppersIds]: Object3D },
}
for (const key of Object.keys(allToppers)) {
let toppers = allToppers[key]
for await (const element of toppers) {
const { scene } = await useGLTF(getModel(element.id, key))
topper_models[key][element.id] = scene
}
}
const { scene: model_pillar_center } = await useGLTF('/models_one/pillar/center.glb')
const { scene: model_pillar_bottom } = await useGLTF('/models_one/pillar/bottom.glb')
const { scene: model_pillar_inner } = await useGLTF('/models_one/pillar/inner.glb')
const { scene: model_pillar_brace } = await useGLTF('/models_one/pillar/brace.glb')
const { scene: model_fastening_top } = await useGLTF('/models_one/fastening/top.glb');
const { scene: model_fastening_side } = await useGLTF('/models_one/fastening/side.glb');
const { scene: model_fixing } = await useGLTF('/models_one/fixing.glb');
const { scene: top_model } = await useGLTF('/models_one/top_100.glb', { draco: true })
// const { scene: lamelle_model } = await useGLTF('/models_one/lamel_100.glb', { draco: true });
const { scene: lamelle_model_standart } = await useGLTF('/models_one/lamel_100.glb', { draco: true });
const { scene: lamelle_model_aristo } = await useGLTF('/models_one/lamel_100_aristo.glb', { draco: true });
const top = ref(top_model)
const top = ref(null)
const pillar_top = ref()
const pillar_center = ref(model_pillar_center)
const pillar_bottom = ref(model_pillar_bottom)
const pillar_inner = ref(model_pillar_inner)
const pillar_brace = ref(model_pillar_brace)
const fastening_top = ref(model_fastening_top)
const fastening_side = ref(model_fastening_side)
const fixing = ref(model_fixing)
const lamelle = ref(lamelle_model_standart)
const pillar_center = ref(null)
const pillar_bottom = ref(null)
const pillar_inner = ref(null)
const pillar_brace = ref(null)
const fastening_top = ref(null)
const fastening_side = ref(null)
const fixing = ref(null)
const lamelle = ref(null)
const setPillarTopper = () => {
let key = 'baseToppers'
if (globalFenceType.value?.type == 'aristo') {
key = 'aristoToppers'
}
pillar_top.value = topper_models[key][pillar_topper.value]
}
setPillarTopper()
watch(pillar_topper, setPillarTopper)
const total = ref(0)
const size = ref(0)
const count = ref(0)
const total = ref((section_count.value + ~~(!!extra_section.value)))
const size = ref(Math.ceil(total.value / 4))
const count = ref((total.value >= 4) ? size.value : total.value)
watch(() => [section_count.value, extra_section.value], () => {
total.value = (section_count.value + ~~(!!extra_section.value))
size.value = Math.ceil(total.value / 4);
count.value = (total.value >= 4) ? size.value : total.value;
const lines_count = (total.value >= 4) ? 4 : 1
const base = seek(scene.value, 'name', 'base')
if (base?.children && base.children.length !== lines_count) {
base.children = [...base?.children.slice(0, lines_count)]
}
const lines = seekAll(scene.value, 'name', 'line')
lines.forEach(line => {
let n = size.value
if (lines_count == 1) {
n = total.value
}
if (line.name.endsWith('_4')) {
n = total.value - size.value * 3
if (n < 0) {
n = 0
}
}
const inner = seek(line, 'name', line.name + '_inner');
if (inner?.children && n < inner?.children.length) {
inner.children = [...inner?.children.slice(0, n)]
}
});
})
const setTarget = (smooth = false) => {
let f = fence_section.value * lamelles_count.value * lamelle_height.value * 0.75;
const max = 2.25
if (f < max) f = max
const target = new Vector3(0, lamelles_count.value * lamelle_height.value * 0.5, 0);
if (smooth) {
goto_target.value = target
goto_cam.value = new Vector3(f, f, f)
} else {
(controls.value as OrbitControlsProps).target = target;
(controls.value as any).update()
goto_cam.value = new Vector3(f, f, f)
}
}
watch([lamelles_count, fence_section, lamelle_height], () => {
setTarget()
open_calc.value = []
})
watch(open_calc, () => {
if (Object.keys(open_calc.value).length == 0) {
setTarget(true)
}
})
const min_for_square = 12;
setTarget()
const loadAll = async () => {
const topper_models = {
baseToppers: {} as { [key: toppersIds]: Object3D },
aristoToppers: {} as { [key: toppersIds]: Object3D },
}
for (const key of Object.keys(allToppers)) {
let toppers = allToppers[key]
for await (const element of toppers) {
const { scene } = await useGLTF(getModel(element.id, key))
topper_models[key][element.id] = scene
}
}
const setLamelleType = () => {
if (globalFenceType.value?.type == 'standart') {
lamelle.value = lamelle_model_standart
lamelle_height.value = 0.115
pillar_topper.value = 0
setPillarTopper()
const { scene: model_pillar_center } = await useGLTF('/models_one/pillar/center.glb')
const { scene: model_pillar_bottom } = await useGLTF('/models_one/pillar/bottom.glb')
const { scene: model_pillar_inner } = await useGLTF('/models_one/pillar/inner.glb')
const { scene: model_pillar_brace } = await useGLTF('/models_one/pillar/brace.glb')
const { scene: model_fastening_top } = await useGLTF('/models_one/fastening/top.glb');
const { scene: model_fastening_side } = await useGLTF('/models_one/fastening/side.glb');
const { scene: model_fixing } = await useGLTF('/models_one/fixing.glb');
const { scene: top_model } = await useGLTF('/models_one/top_100.glb', { draco: true })
// const { scene: lamelle_model } = await useGLTF('/models_one/lamel_100.glb', { draco: true });
const { scene: lamelle_model_standart } = await useGLTF('/models_one/lamel_100.glb', { draco: true });
const { scene: lamelle_model_aristo } = await useGLTF('/models_one/lamel_100_aristo.glb', { draco: true });
top.value = top_model
pillar_center.value = model_pillar_center
pillar_bottom.value = model_pillar_bottom
pillar_inner.value = model_pillar_inner
pillar_brace.value = model_pillar_brace
fastening_top.value = model_fastening_top
fastening_side.value = model_fastening_side
fixing.value = model_fixing
lamelle.value = lamelle_model_standart
const setPillarTopper = () => {
let key = 'baseToppers'
if (globalFenceType.value?.type == 'aristo') {
key = 'aristoToppers'
}
pillar_top.value = topper_models[key][pillar_topper.value]
}
if (globalFenceType.value?.type == 'aristo') {
lamelle.value = lamelle_model_aristo
lamelle_height.value = 0.196
pillar_topper.value = 0
setPillarTopper()
setPillarTopper()
watch(pillar_topper, setPillarTopper)
total.value = (section_count.value + ~~(!!extra_section.value))
size.value = Math.ceil(total.value / 4)
count.value = (total.value >= 4) ? size.value : total.value
watch(() => [section_count.value, extra_section.value], () => {
total.value = (section_count.value + ~~(!!extra_section.value))
size.value = Math.ceil(total.value / 4);
count.value = (total.value >= 4) ? size.value : total.value;
const lines_count = (total.value >= 4) ? 4 : 1
const base = seek(scene.value, 'name', 'base')
if (base?.children && base.children.length !== lines_count) {
base.children = [...base?.children.slice(0, lines_count)]
}
const lines = seekAll(scene.value, 'name', 'line')
lines.forEach(line => {
let n = size.value
if (lines_count == 1) {
n = total.value
}
if (line.name.endsWith('_4')) {
n = total.value - size.value * 3
if (n < 0) {
n = 0
}
}
const inner = seek(line, 'name', line.name + '_inner');
if (inner?.children && n < inner?.children.length) {
inner.children = [...inner?.children.slice(0, n)]
}
});
})
const setTarget = (smooth = false) => {
let f = fence_section.value * lamelles_count.value * lamelle_height.value * 0.75;
const max = 2.25
if (f < max) f = max
const target = new Vector3(0, lamelles_count.value * lamelle_height.value * 0.5, 0);
if (smooth) {
goto_target.value = target
goto_cam.value = new Vector3(f, f, f)
} else {
(controls.value as OrbitControlsProps).target = target;
(controls.value as any).update()
goto_cam.value = new Vector3(f, f, f)
}
}
watch([lamelles_count, fence_section, lamelle_height], () => {
setTarget()
open_calc.value = []
})
watch(open_calc, () => {
if (Object.keys(open_calc.value).length == 0) {
setTarget(true)
}
})
setTarget()
const setLamelleType = () => {
if (globalFenceType.value?.type == 'standart') {
lamelle.value = lamelle_model_standart
lamelle_height.value = 0.115
pillar_topper.value = 0
setPillarTopper()
}
if (globalFenceType.value?.type == 'aristo') {
lamelle.value = lamelle_model_aristo
lamelle_height.value = 0.196
pillar_topper.value = 0
setPillarTopper()
}
}
setLamelleType()
watch(() => globalFenceType.value?.id, setLamelleType)
}
setLamelleType()
watch(() => globalFenceType.value?.id, setLamelleType)
onMounted(async () => { await loadAll() })
</script>
<template>
<TresGroup name="base">

55
components/scene.vue Normal file
View File

@ -0,0 +1,55 @@
<script setup>
const props = defineProps({
canvasProps: {
type: Object,
default: () => ({}),
},
cameraProps: {
type: Object,
default: () => ({}),
}
});
const container = ref(null);
const isIntersecting = ref(true);
let observer;
// Вычисляем renderMode на основе видимости
const renderMode = computed(() => (isIntersecting.value ? 'always' : 'never'));
const startObserver = () => {
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
isIntersecting.value = entry.isIntersecting;
});
},
{ threshold: 0.1 } // Настройте порог видимости по вашему усмотрению
);
if (container.value) {
observer.observe(container.value);
}
}
onMounted(async () => {
await nextTick(); // Ждём завершения рендеринга
startObserver(); // Запускаем IntersectionObserver
});
onBeforeUnmount(() => {
if (observer) {
observer.disconnect();
}
});
</script>
<template>
<div ref="container" class="h-full">
<Suspense>
<TresCanvas v-bind="canvasProps" :render-mode="renderMode" :key="renderMode">
<ModelEnv />
<Suspense>
<slot />
</Suspense>
</TresCanvas>
</Suspense>
</div>
</template>

View File

@ -29,7 +29,7 @@ export default defineNuxtConfig({
runtimeConfig: {
public: {
// apiBase: process.env.mode == 'DEVELOPMENT' ? "http://localhost:8000" : "https://mns.kustarshina.ru/kp",
apiBase: process.env.mode == 'DEVELOPMENT' ? "http://mns.dev.kustarshina.ru/kp" : "https://mns.kustarshina.ru/kp",
apiBase: process.env.mode == 'DEVELOPMENT' ? "http://mns.dev.kustarshina.ru" : "https://mns.kustarshina.ru/kp",
// apiBase: 'http://localhost:8000',
imgBase: 'https://mns.kustarshina.ru',
baseUrl: '',