dev #90

Merged
ksenia_mikhailova merged 20 commits from dev into main 2025-03-20 14:15:19 +03:00
6 changed files with 144 additions and 42 deletions
Showing only changes of commit 01cb9440b2 - Show all commits

View File

@ -3,6 +3,9 @@ import { TresCanvas } from '@tresjs/core'
import { Stats, OrbitControls } from '@tresjs/cientos' import { Stats, OrbitControls } from '@tresjs/cientos'
import { degToRad } from 'three/src/math/MathUtils.js'; import { degToRad } from 'three/src/math/MathUtils.js';
const container = ref<HTMLElement | null>(null);
const { isIntersecting, startObserver, stopObserver } = useSceneVisibility();
const controlsState = reactive({ const controlsState = reactive({
position: { x: 0, y: 0, z: 0 }, position: { x: 0, y: 0, z: 0 },
enablePan: false, enablePan: false,
@ -17,9 +20,21 @@ const cameraStat = reactive({
aspect: 1920 / 600, aspect: 1920 / 600,
// fov: 40, // fov: 40,
}) })
const renderMode = computed(() => (isIntersecting.value ? 'always' : 'manual'));
onMounted(async () => {
if (container.value) {
await nextTick()
startObserver(container.value);
}
});
onBeforeUnmount(() => {
stopObserver();
});
</script> </script>
<template> <template>
<div class="calc"> <div class="calc" ref="container">
<ClientOnly fallback-tag="div"> <ClientOnly fallback-tag="div">
<template #fallback> <template #fallback>
<div class="fallback"> <div class="fallback">
@ -27,9 +42,12 @@ const cameraStat = reactive({
</div> </div>
</template> </template>
<Loader /> <Loader />
<Scene :canvasProps="{ clearColor: '#e2e8f0' }"> <TresCanvas clear-color="#e2e8f0" :render-mode="renderMode" :key="renderMode">
<TresPerspectiveCamera v-bind="cameraStat" ref="camera" /> <TresPerspectiveCamera v-bind="cameraStat" ref="camera" />
<OrbitControls v-bind="controlsState" make-default /> <OrbitControls v-bind="controlsState" make-default />
<Suspense>
<ModelEnv />
</Suspense>
<Suspense> <Suspense>
<ModelSmoothCamera /> <ModelSmoothCamera />
</Suspense> </Suspense>
@ -38,7 +56,7 @@ const cameraStat = reactive({
<ModelParametric /> <ModelParametric />
</Suspense> </Suspense>
</TresGroup> </TresGroup>
</Scene> </TresCanvas>
</ClientOnly> </ClientOnly>
</div> </div>
</template> </template>

View File

@ -3,6 +3,9 @@ import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos' import { OrbitControls } from '@tresjs/cientos'
import { Vector3 } from 'three'; import { Vector3 } from 'three';
const container = ref<HTMLElement | null>(null);
const { isIntersecting, startObserver, stopObserver } = useSceneVisibility();
const camera = ref() const camera = ref()
const controls = ref() const controls = ref()
const controlsState = reactive({ const controlsState = reactive({
@ -25,20 +28,39 @@ const changeDistance = (v = 1) => {
camera.value.position.normalize().multiplyScalar(r) camera.value.position.normalize().multiplyScalar(r)
} }
} }
const renderMode = computed(() => (isIntersecting.value ? 'always' : 'manual'));
onMounted(async () => {
if (container.value) {
await nextTick()
startObserver(container.value);
}
});
onBeforeUnmount(() => {
stopObserver();
});
</script> </script>
<template> <template>
<div class="h-96 relative"> <Suspense>
<div ref="container" class="h-96 relative">
<ClientOnly fallback-tag="div"> <ClientOnly fallback-tag="div">
<template #fallback> <template #fallback>
<div class="fallback"> <div class="fallback">
Загрузка 3D модели Загрузка 3D модели
</div> </div>
</template> </template>
<Scene :canvasProps="{ height: '600' }"> <TresCanvas height="600" :render-mode="renderMode" :key="renderMode">
<TresPerspectiveCamera :position="[-7, 2, 4]" ref="camera" /> <TresPerspectiveCamera :position="[-7, 2, 4]" ref="camera" />
<OrbitControls v-bind="controlsState" ref="controls" make-default /> <OrbitControls v-bind="controlsState" ref="controls" make-default />
<Suspense>
<ModelEnv />
</Suspense>
<Suspense>
<ModelDiagram /> <ModelDiagram />
</Scene> </Suspense>
</TresCanvas>
</ClientOnly> </ClientOnly>
<div class="canvas-icons"> <div class="canvas-icons">
<a href="#" @click.prevent="toggleExpState"> <a href="#" @click.prevent="toggleExpState">
@ -55,6 +77,7 @@ const changeDistance = (v = 1) => {
</a> </a>
</div> </div>
</div> </div>
</Suspense>
</template> </template>
<style scoped> <style scoped>

View File

@ -8,7 +8,7 @@ import {
import { GainMapLoader, } from '@monogrid/gainmap-js' import { GainMapLoader, } from '@monogrid/gainmap-js'
import { useLoop } from '@tresjs/core'; import { useLoop } from '@tresjs/core';
const { scene, renderer, camera } = useTresContext() const { scene, renderer, camera } = useTresContext()
const {onBeforeRender} = useLoop() const { onBeforeRender } = useLoop()
renderer.value.toneMapping = CineonToneMapping renderer.value.toneMapping = CineonToneMapping
renderer.value.toneMappingExposure = 1 renderer.value.toneMappingExposure = 1
@ -18,6 +18,7 @@ renderer.value.shadowMap.type = PCFSoftShadowMap
const pmremGenerator = new PMREMGenerator(renderer.value); const pmremGenerator = new PMREMGenerator(renderer.value);
pmremGenerator.compileEquirectangularShader(); pmremGenerator.compileEquirectangularShader();
onMounted(async () => { onMounted(async () => {
const loader = new GainMapLoader(renderer.value) const loader = new GainMapLoader(renderer.value)
const result = await loader.loadAsync([ const result = await loader.loadAsync([
@ -35,14 +36,15 @@ onMounted(async () => {
scene.value.environmentIntensity = 1.25 scene.value.environmentIntensity = 1.25
scene.value.environmentRotation.z = 0.25 scene.value.environmentRotation.z = 0.25
result.renderTarget.texture.dispose(); result.renderTarget.texture.dispose();
})
onBeforeRender(()=>{ onBeforeRender(() => {
if(camera.value) { if (camera.value) {
const cameraDirection = new Vector3() const cameraDirection = new Vector3()
camera.value.getWorldDirection(cameraDirection); camera.value.getWorldDirection(cameraDirection);
const angle = Math.atan2(cameraDirection.z, cameraDirection.x); const angle = Math.atan2(cameraDirection.z, cameraDirection.x);
scene.value.environmentRotation.z = angle + 0.25 scene.value.environmentRotation.z = angle + 0.25
} }
})
}) })
</script> </script>
<template></template> <template></template>

View File

@ -0,0 +1,57 @@
// useSceneVisibility.ts
import { ref, onMounted, onBeforeUnmount } from 'vue';
export function useSceneVisibility() {
const isIntersecting = ref(false); // Состояние видимости
let observer: IntersectionObserver | null = null;
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
const startObserver = (element: HTMLElement) => {
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (debounceTimeout) {
clearTimeout(debounceTimeout); // Очищаем предыдущий таймер
}
// Устанавливаем новый таймер
debounceTimeout = setTimeout(() => {
isIntersecting.value = entry.isIntersecting;
}, 100); // Задержка в 300 мс
});
},
{ threshold: 0.05 } // Порог видимости
);
if (element) {
observer.observe(element);
}
};
const stopObserver = () => {
if (observer) {
observer.disconnect();
observer = null;
}
if (debounceTimeout) {
clearTimeout(debounceTimeout); // Очищаем таймер при остановке наблюдателя
debounceTimeout = null;
}
};
onMounted(() => {
// Инициализация наблюдателя при монтировании
});
onBeforeUnmount(() => {
// Очистка наблюдателя при размонтировании
stopObserver();
});
return {
isIntersecting,
startObserver,
stopObserver,
};
}

View File

@ -51,9 +51,9 @@ export default defineNuxtConfig({
vite: { vite: {
assetsInclude: ['**/*.glb', '**/*.gltf'], assetsInclude: ['**/*.glb', '**/*.gltf'],
build: { build: {
target: 'esnext' target: 'esnext',
// minify: 'esbuild' // minify: 'esbuild'
// minify: false minify: false,
}, },
}, },
robots: { robots: {

View File

@ -133,7 +133,9 @@ watch(openTab, () => {
</div> </div>
<div class="container gap-4"> <div class="container gap-4">
<div class="col-span-full xl:col-span-8"> <div class="col-span-full xl:col-span-8">
<Suspense>
<ExpDiagram /> <ExpDiagram />
</Suspense>
</div> </div>
<div class="col-span-full xl:col-span-4 prose"> <div class="col-span-full xl:col-span-4 prose">
<span v-html="advantagesText"></span> <span v-html="advantagesText"></span>