bx-865-apps #1
|
@ -505,6 +505,22 @@
|
||||||
"detail": "object.models",
|
"detail": "object.models",
|
||||||
"documentation": {}
|
"documentation": {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "MinValueValidator",
|
||||||
|
"importPath": "django.core.validators",
|
||||||
|
"description": "django.core.validators",
|
||||||
|
"isExtraImport": true,
|
||||||
|
"detail": "django.core.validators",
|
||||||
|
"documentation": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MaxValueValidator",
|
||||||
|
"importPath": "django.core.validators",
|
||||||
|
"description": "django.core.validators",
|
||||||
|
"isExtraImport": true,
|
||||||
|
"detail": "django.core.validators",
|
||||||
|
"documentation": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "django_filters",
|
"label": "django_filters",
|
||||||
"kind": 6,
|
"kind": 6,
|
||||||
|
@ -1041,7 +1057,7 @@
|
||||||
"kind": 6,
|
"kind": 6,
|
||||||
"importPath": "back.object.models",
|
"importPath": "back.object.models",
|
||||||
"description": "back.object.models",
|
"description": "back.object.models",
|
||||||
"peekOfCode": "class Element3D(models.Model):\n parent = models.ForeignKey(\"self\", on_delete=models.PROTECT, blank=True, null=True)\n model_file = models.FileField(upload_to=group_based_upload_to)\n name = models.CharField(max_length=255)\n description = models.TextField()\n def __str__(self):\n return self.name\nclass ClickableArea(models.Model):\n name = models.CharField(max_length=255)\n description = models.TextField()",
|
"peekOfCode": "class Element3D(models.Model):\n parent = models.ForeignKey(\"self\", on_delete=models.PROTECT, blank=True, null=True)\n model_file = models.FileField(upload_to=group_based_upload_to)\n name = models.CharField(max_length=255)\n description = models.TextField()\n min_distance = models.IntegerField(\n validators=[MinValueValidator(1), MaxValueValidator(200)],\n blank=True,\n null=True\n )",
|
||||||
"detail": "back.object.models",
|
"detail": "back.object.models",
|
||||||
"documentation": {}
|
"documentation": {}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
VITE_SERVER_URL='http://localhost:8000'
|
# VITE_SERVER_URL='http://localhost:8000'
|
||||||
|
VITE_SERVER_URL='https://demo.kustarshina.ru'
|
||||||
VITE_IMAGE_URL='https://demo.kustarshina.ru'
|
VITE_IMAGE_URL='https://demo.kustarshina.ru'
|
|
@ -19,6 +19,7 @@ declare module 'vue' {
|
||||||
IMdiShop: typeof import('~icons/mdi/shop')['default']
|
IMdiShop: typeof import('~icons/mdi/shop')['default']
|
||||||
IMdiVideo3d: typeof import('~icons/mdi/video3d')['default']
|
IMdiVideo3d: typeof import('~icons/mdi/video3d')['default']
|
||||||
Item: typeof import('./src/components/Floorplan/item.vue')['default']
|
Item: typeof import('./src/components/Floorplan/item.vue')['default']
|
||||||
|
Load_models: typeof import('./src/components/Promo/load_models.vue')['default']
|
||||||
Main: typeof import('./src/components/Promo/main.vue')['default']
|
Main: typeof import('./src/components/Promo/main.vue')['default']
|
||||||
ModelItem: typeof import('./src/components/Promo/modelItem.vue')['default']
|
ModelItem: typeof import('./src/components/Promo/modelItem.vue')['default']
|
||||||
Models: typeof import('./src/components/Promo/models.vue')['default']
|
Models: typeof import('./src/components/Promo/models.vue')['default']
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { IMAGE_URL, SERVER_URL, } from '../../constants'
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { Box3, Vector3 } from 'three';
|
||||||
|
|
||||||
|
import { useTresContext } from '@tresjs/core';
|
||||||
|
import { useGLTF } from '@tresjs/cientos'
|
||||||
|
|
||||||
|
const max_size = reactive({
|
||||||
|
x: 0, y: 0, z: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
interface element3DType {
|
||||||
|
id: number
|
||||||
|
model_file: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
parent?: number,
|
||||||
|
min_distance?: number,
|
||||||
|
max_distance?: number,
|
||||||
|
}
|
||||||
|
interface model3DType {
|
||||||
|
modelUrl?: string,
|
||||||
|
modelFile?: any
|
||||||
|
}
|
||||||
|
const models = ref<model3DType[]>([])
|
||||||
|
const { camera, controls } = useTresContext()
|
||||||
|
const loadModels = async () => {
|
||||||
|
const res = await fetch(`${SERVER_URL}/api/obj/element/?parent__isnull=True`)
|
||||||
|
const data = await res.json() as element3DType[]
|
||||||
|
const distance = {
|
||||||
|
min: controls.value.minDistance,
|
||||||
|
max: controls.value.maxDistance == Infinity ? 1 : controls.value.maxDistance,
|
||||||
|
}
|
||||||
|
console.log(camera)
|
||||||
|
console.log(controls)
|
||||||
|
for (let index = 0; index < data.length; index++) {
|
||||||
|
const element = data[index];
|
||||||
|
const item = {} as model3DType
|
||||||
|
|
||||||
|
item.modelUrl = `${IMAGE_URL}/${element.model_file}`
|
||||||
|
let { scene: loaded_scene } = await useGLTF(item.modelUrl)
|
||||||
|
item.modelFile = loaded_scene
|
||||||
|
|
||||||
|
models.value.push(item)
|
||||||
|
|
||||||
|
if (element.min_distance && element.min_distance > distance.min) distance.min = element.min_distance
|
||||||
|
if (element.max_distance && element.max_distance > distance.max) distance.max = element.max_distance
|
||||||
|
|
||||||
|
const box = new Box3();
|
||||||
|
box.expandByObject(loaded_scene.children[0]);
|
||||||
|
const box_size = new Vector3();
|
||||||
|
box.getSize(box_size)
|
||||||
|
if (max_size.x > box_size.x) max_size.x = box_size.x
|
||||||
|
if (max_size.y > box_size.y) max_size.y = box_size.y
|
||||||
|
if (max_size.z > box_size.z) max_size.z = box_size.z
|
||||||
|
}
|
||||||
|
controls.value.maxDistance = distance.max
|
||||||
|
controls.value.minDistance = distance.min
|
||||||
|
controls.value._needsUpdate = true
|
||||||
|
controls.value.update(1)
|
||||||
|
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
loadModels()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<TresGroup v-for="item in models">
|
||||||
|
<Suspense>
|
||||||
|
<ModelItem v-bind="item" />
|
||||||
|
</Suspense>
|
||||||
|
</TresGroup>
|
||||||
|
</template>
|
|
@ -1,104 +1,67 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { IMAGE_URL, SERVER_URL, } from '../../constants'
|
import { reactive, ref } from 'vue';
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import type { Ref } from 'vue'
|
||||||
import { Vector3 } from 'three';
|
import { Vector3 } from 'three';
|
||||||
|
|
||||||
import { TresCanvas } from '@tresjs/core';
|
import { TresCanvas } from '@tresjs/core';
|
||||||
import { CameraControls, useGLTF, useProgress } from '@tresjs/cientos'
|
import { CameraControls, useProgress, StatsGl } from '@tresjs/cientos'
|
||||||
|
|
||||||
import Env from './env.vue'
|
import Env from './env.vue'
|
||||||
import ModelItem from './modelItem.vue';
|
import LoadModels from './load_models.vue'
|
||||||
|
|
||||||
const minPan = new Vector3(-10, 1, -5);
|
|
||||||
const maxPan = new Vector3(5, 1, 5);
|
|
||||||
const _v = new Vector3();
|
const _v = new Vector3();
|
||||||
|
|
||||||
const onChange = (e: any) => {
|
const onChange = (e: any) => {
|
||||||
|
// console.log(e._camera.position.normalize())
|
||||||
_v.copy(e._target);
|
_v.copy(e._target);
|
||||||
e._target.clamp(minPan, maxPan);
|
// e._target.clamp(minPan, maxPan);
|
||||||
_v.sub(e._target);
|
_v.sub(e._target);
|
||||||
e._camera.position.sub(_v);
|
e._camera.position.sub(_v);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cameraPosition = [-6, 4, 25] as unknown as Vector3
|
const camera = ref()
|
||||||
|
const cameraPosition = ref([1, 1, 1]) as unknown as Ref<Vector3>
|
||||||
|
|
||||||
const controlsState = reactive({
|
const controlsState = reactive({
|
||||||
minDistance: 2,
|
// minDistance: 2,
|
||||||
maxDistance: 30,
|
// maxDistance: 30,
|
||||||
maxPolarAngle: (Math.PI / 2) - 0.02,
|
maxPolarAngle: (Math.PI / 2) - 0.02,
|
||||||
maxZoom: 1,
|
enableZoom: false,
|
||||||
minZoom: 1,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const { hasFinishLoading, progress } = await useProgress()
|
const { hasFinishLoading, progress } = await useProgress()
|
||||||
|
|
||||||
const point_light = reactive({
|
const point_light = reactive({
|
||||||
intensity: 10000,
|
intensity: 1000,
|
||||||
position: new Vector3(-100, 5, 5),
|
position: new Vector3(-100, 50, 5),
|
||||||
})
|
})
|
||||||
interface element3DType {
|
|
||||||
id: number
|
|
||||||
model_file: string
|
|
||||||
name: string
|
|
||||||
description: string
|
|
||||||
parent?: number,
|
|
||||||
min_distance?: number,
|
|
||||||
max_distance?: number,
|
|
||||||
}
|
|
||||||
interface model3DType {
|
|
||||||
modelUrl?: string,
|
|
||||||
modelFile?: any
|
|
||||||
}
|
|
||||||
const models = ref<model3DType[]>([])
|
|
||||||
const loadModels = async () => {
|
|
||||||
const res = await fetch(`${SERVER_URL}/api/obj/element/?parent__isnull=True`)
|
|
||||||
const data = await res.json() as element3DType[]
|
|
||||||
const distance = {
|
|
||||||
min: controlsState.minDistance,
|
|
||||||
max: controlsState.maxDistance,
|
|
||||||
}
|
|
||||||
for (let index = 0; index < data.length; index++) {
|
|
||||||
const element = data[index];
|
|
||||||
const item = {} as model3DType
|
|
||||||
|
|
||||||
item.modelUrl = `${IMAGE_URL}/${element.model_file}`
|
|
||||||
let { scene: loaded_scene } = await useGLTF(item.modelUrl)
|
|
||||||
item.modelFile = loaded_scene
|
|
||||||
|
|
||||||
models.value.push(item)
|
|
||||||
|
|
||||||
if (element.min_distance && element.min_distance > distance.min) distance.min = element.min_distance
|
|
||||||
if (element.max_distance && element.max_distance > distance.max) distance.max = element.max_distance
|
|
||||||
}
|
|
||||||
controlsState.maxDistance = distance.max
|
|
||||||
controlsState.minDistance = distance.min
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
loadModels()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="[{ 'invisible': !!hasFinishLoading }, 'loader']">
|
<div :class="[{ 'invisible': !!hasFinishLoading }, 'loader']">
|
||||||
Загрузка {{ progress }}%
|
Загрузка {{ progress }}%
|
||||||
</div>
|
</div>
|
||||||
<div :class="[{ 'invisible': !hasFinishLoading }]">
|
<div :class="[{ 'invisible': !hasFinishLoading }]">
|
||||||
<TresCanvas window-size>
|
<TresCanvas shadows window-size>
|
||||||
<TresPerspectiveCamera :position="cameraPosition" />
|
<Suspense>
|
||||||
|
<StatsGl />
|
||||||
|
</Suspense>
|
||||||
|
<TresPerspectiveCamera :position="cameraPosition" ref="camera" />
|
||||||
<CameraControls v-bind="controlsState" @change="onChange" make-default />
|
<CameraControls v-bind="controlsState" @change="onChange" make-default />
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<Env />
|
<Env />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<TresGroup v-for="item in models">
|
<Suspense>
|
||||||
<Suspense>
|
<LoadModels />
|
||||||
<ModelItem v-bind="item" />
|
</Suspense>
|
||||||
</Suspense>
|
<TresMesh cast-shadow>
|
||||||
</TresGroup>
|
|
||||||
<TresMesh>
|
|
||||||
<TresBoxGeometry :args="[1, 1, 1]" />
|
<TresBoxGeometry :args="[1, 1, 1]" />
|
||||||
<TresMeshStandardMaterial />
|
<TresMeshStandardMaterial />
|
||||||
</TresMesh>
|
</TresMesh>
|
||||||
<TresPointLight v-bind="point_light" />
|
<TresMesh :position-y="0" :rotate-x="-Math.PI / 2" receive-shadow>
|
||||||
<TresAmbientLight :intensity="1" />
|
<TresPlaneGeometry :args="[200, 200]" />
|
||||||
|
<TresShadowMaterial :opacity="0.2" />
|
||||||
|
</TresMesh>
|
||||||
|
<TresPointLight v-bind="point_light" cast-shadow />
|
||||||
</TresCanvas>
|
</TresCanvas>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -21,9 +21,7 @@ function shadows_and_pos(scene: any) {
|
||||||
shadows_and_pos(scene)
|
shadows_and_pos(scene)
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<TresGroup >
|
<TresMesh>
|
||||||
<TresMesh cast-shadow receive-shadow>
|
<primitive :object="scene" />
|
||||||
<primitive :object="scene" />
|
</TresMesh>
|
||||||
</TresMesh>
|
|
||||||
</TresGroup>
|
|
||||||
</template>
|
</template>
|
Loading…
Reference in New Issue