mns
/
urna
forked from mns/mini-skamja
4
0
Fork 0
This commit is contained in:
Kseninia Mikhaylova 2025-03-13 16:48:51 +03:00
parent 3ba9649952
commit 2faf0979fd
6 changed files with 164 additions and 60 deletions

View File

@ -174,7 +174,10 @@ a[href^="#"] {
@apply py-10;
&_imgbg {
@apply py-0 bg-no-repeat bg-cover bg-bottom h-[50vh] min-h-[600px];
@apply relative py-0 bg-no-repeat bg-[auto_100%] bg-center h-[50vh] min-h-[300px] bg-transparent overflow-hidden;
img {
@apply absolute top-0 right-0 bottom-0 left-0 blur-lg w-full -z-10 scale-110;
}
}
&_calc {

View File

@ -1,14 +1,38 @@
<script setup lang="ts">
//@ts-ignore
import { useGLTF } from '@tresjs/cientos'
import { Vector3 } from 'three';
import { useTresContext } from '@tresjs/core'
import { Vector3 } from 'three'
import { ref, onMounted } from 'vue'
const { scene: bench1 } = await useGLTF('/models/bench2_export-v1.glb')
const { camera, controls } = useTresContext()
const { scene: obj } = await useGLTF('/models/bench2_export-v1.glb')
const scale = ref(1) // Масштаб объекта
onMounted(() => {
if (obj && camera.value && controls.value) {
const distance = 10
const cameraOffset = { x: 1, y: 0.75, z: -1.25 } // Смещение камеры
// Вычисляем масштаб и позицию камеры
const { scale: objectScale } = calculateScaleToFit(
obj,
camera.value as any,
controls.value as any,
distance,
cameraOffset
)
scale.value = objectScale
}
})
</script>
<template>
<Suspense>
<TresGroup :position-y="0" :scale="new Vector3(2, 2, 2)">
<ModelItem :model="bench1" :target="[0, 0, 0]" />
<TresGroup :position-y="0" :scale="new Vector3(scale, scale, scale)">
<ModelItem :model="obj" :target="[0, 0, 0]" />
</TresGroup>
</Suspense>
</template>
</template>

View File

@ -1,14 +1,38 @@
<script setup lang="ts">
//@ts-ignore
import { useGLTF } from '@tresjs/cientos'
import { Vector3 } from 'three';
import { useTresContext } from '@tresjs/core'
import { Vector3 } from 'three'
import { ref, onMounted } from 'vue'
const { scene: bench1 } = await useGLTF('/models/bench_export-v1.glb')
const { camera, controls } = useTresContext()
const { scene: obj } = await useGLTF('/models/bench_export-v1.glb')
const scale = ref(1) // Масштаб объекта
onMounted(() => {
if (obj && camera.value && controls.value) {
const distance = 10
const cameraOffset = { x: -1, y: 0.75, z: -1.25 } // Смещение камеры
// Вычисляем масштаб и позицию камеры
const { scale: objectScale } = calculateScaleToFit(
obj,
camera.value as any,
controls.value as any,
distance,
cameraOffset
)
scale.value = objectScale
}
})
</script>
<template>
<Suspense>
<TresGroup :position-y="0" :scale="new Vector3(2, 2, 2)">
<ModelItem :model="bench1" :target="[0, 0, 0]" />
<TresGroup :position-y="0" :scale="new Vector3(scale, scale, scale)">
<ModelItem :model="obj" :target="[0, 0, 0]" />
</TresGroup>
</Suspense>
</template>
</template>

View File

@ -14,32 +14,34 @@ const props = defineProps({
}
})
const camera = ref()
const controls = ref()
const controlsState = reactive({
minDistance: 2,
maxDistance: 10,
// minDistance: 2,
// maxDistance: 10,
enablePan: false,
enableZoom: false,
maxPolarAngle: Math.PI / 2 - 0.2
})
const toggleModal = () => {}
</script>
<template>
<div class="relative h-[600px] max-h-screen">
<ClientOnly fallback-tag="div">
<template #fallback>
<div class="fallback">Загрузка 3D модели</div>
</template>
<TresCanvas height="600">
<TresPerspectiveCamera :position="new Vector3(-7, 2, 4)" ref="camera" />
<OrbitControls v-bind="controlsState" ref="controls" make-default />
<ModelEnv />
<Suspense>
<component :is="types[props.type]" />
</Suspense>
</TresCanvas>
</ClientOnly>
<div>
<div class="relative h-[600px] max-h-screen">
<ClientOnly fallback-tag="div">
<template #fallback>
<div class="fallback">Загрузка 3D модели</div>
</template>
<TresCanvas height="600">
<TresPerspectiveCamera />
<OrbitControls v-bind="controlsState" make-default />
<ModelEnv />
<Suspense>
<component :is="types[props.type]" />
</Suspense>
</TresCanvas>
</ClientOnly>
</div>
<button @click.prevent="toggleModal">Рассчитать</button>
</div>
</template>

View File

@ -46,7 +46,7 @@ const delivery = computed(() =>
<div class="siteblock-image">
<NuxtImg
:src="[imgBase, page.image].join('/')"
alt="разные цвета забора"
:alt="page.title"
title=""
format="webp"
/>
@ -63,40 +63,40 @@ const delivery = computed(() =>
>
<NuxtImg
:src="[imgBase, page.image].join('/')"
class="invisible"
alt="отзыв"
title=""
:alt="page.title"
format="webp"
loading="lazy"
/>
</div>
<div class="container" :id="page.slug">
<template v-for="item in review?.slice(0, 3)">
<div class="review">
<div class="review-image">
<NuxtImg
:src="[imgBase, item.image].join('/')"
:alt="item.text"
title=""
format="webp"
loading="lazy"
/>
<div class="siteblock bg-white">
<div class="container" :id="page.slug">
<template v-for="item in review?.slice(0, 3)">
<div class="review">
<div class="review-image">
<NuxtImg
:src="[imgBase, item.image].join('/')"
:alt="item.text"
title=""
format="webp"
loading="lazy"
/>
</div>
<div class="review-content">
{{ item.comment }}
</div>
<div class="review-title">
{{ item.text }}
</div>
</div>
<div class="review-content">
{{ item.comment }}
</div>
<div class="review-title">
{{ item.text }}
</div>
</div>
</template>
</template>
</div>
</div>
</template>
<template v-if="page.slug == 'advantages'">
<div class="siteblock bg-white" :id="page.slug">
<div class="container gap-4">
<div class="col-span-full xl:col-span-8">
<ModelScene />
<ModelScene type="bench" />
</div>
<div class="col-span-full xl:col-span-4 prose">
<span v-html="marked.parse(page.content || '')"></span>
@ -113,9 +113,6 @@ const delivery = computed(() =>
>
<NuxtImg
:src="[imgBase, page.image].join('/')"
class="invisible"
alt="коричневый забор"
title=""
format="webp"
loading="lazy"
/>
@ -140,9 +137,6 @@ const delivery = computed(() =>
>
<NuxtImg
:src="[imgBase, page.image].join('/')"
class="invisible"
alt="коричневый забор"
title=""
format="webp"
loading="lazy"
/>

View File

@ -0,0 +1,57 @@
import { Box3, PerspectiveCamera, Vector3 } from 'three'
import { degToRad } from 'three/src/math/MathUtils.js';
/**
* Вычисляет масштаб объекта и позицию камеры, чтобы объект полностью помещался в видимой области.
* @param object - Объект Three.js (например, загруженная модель).
* @param camera - Экземпляр камеры.
* @param controls - Экземпляр OrbitControls.
* @param distance - Расстояние от камеры до объекта.
* @param cameraOffset - Коэффициенты смещения камеры (x, y, z).
*/
export default function (
object: any,
camera: PerspectiveCamera,
controls: any,
distance: number,
cameraOffset: { x: number; y: number; z: number }
) {
// Обновляем мировую матрицу объекта
object.updateWorldMatrix(true, true)
const fov = camera.fov // Угол обзора камеры
const aspect = camera.aspect // Соотношение сторон
const bbox = new Box3().setFromObject(object) // Вычисляем bounding box
const center = new Vector3()
bbox.getCenter(center) // Центр объекта
const size = new Vector3()
bbox.getSize(size) // Размеры объекта
// Рассчитываем масштаб, чтобы объект полностью помещался в видимой области
const vFOV = degToRad(fov) // Угол обзора в радианах
const visibleHeight = 2 * Math.tan(vFOV / 2) * distance // Видимая высота
const visibleWidth = visibleHeight * aspect // Видимая ширина
const scaleX = visibleWidth / size.x
const scaleY = visibleHeight / size.y
const scaleZ = visibleWidth / size.z
const scale = Math.min(scaleX, scaleY, scaleZ)
// Позиционируем камеру с учетом смещения
camera.position.set(
center.x + distance * cameraOffset.x,
center.y + distance * cameraOffset.y,
center.z + distance * cameraOffset.z
)
// Устанавливаем цель для OrbitControls
if (controls) {
controls.target.set(center.x, center.y, center.z)
controls.update() // Обновляем контроллы
}
return { scale, center }
}