bx-1140-postprocessing #11
File diff suppressed because it is too large
Load Diff
|
@ -61,6 +61,7 @@ CORS_ORIGIN_WHITELIST = [
|
||||||
"http://127.0.0.1",
|
"http://127.0.0.1",
|
||||||
"http://192.168.103.159",
|
"http://192.168.103.159",
|
||||||
"http://192.168.103.159:3000",
|
"http://192.168.103.159:3000",
|
||||||
|
"http://192.168.103.159:5173",
|
||||||
"http://192.168.103.159:8000",
|
"http://192.168.103.159:8000",
|
||||||
"http://front:4173",
|
"http://front:4173",
|
||||||
"http://front:5173",
|
"http://front:5173",
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
VITE_SERVER_URL='https://demo.kustarshina.ru'
|
VITE_SERVER_URL='https://demo.kustarshina.ru'
|
||||||
VITE_IMAGE_URL='https://demo.kustarshina.ru'
|
VITE_IMAGE_URL='https://demo.kustarshina.ru'
|
||||||
VITE_SERVER_URL='http://localhost:8000'
|
VITE_SERVER_URL='http://192.168.103.159:8000'
|
|
@ -7,6 +7,7 @@ export {}
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
Composer: typeof import('./src/components/Promo/composer.vue')['default']
|
||||||
Env: typeof import('./src/components/Promo/env.vue')['default']
|
Env: typeof import('./src/components/Promo/env.vue')['default']
|
||||||
Floorplan: typeof import('./src/components/Floorplan/index.vue')['default']
|
Floorplan: typeof import('./src/components/Floorplan/index.vue')['default']
|
||||||
Gallery: typeof import('./src/components/Promo/gallery.vue')['default']
|
Gallery: typeof import('./src/components/Promo/gallery.vue')['default']
|
||||||
|
@ -25,6 +26,7 @@ declare module 'vue' {
|
||||||
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']
|
||||||
|
Post_pocessing: typeof import('./src/components/Promo/post_pocessing.vue')['default']
|
||||||
Projects: typeof import('./src/components/Projects.vue')['default']
|
Projects: typeof import('./src/components/Projects.vue')['default']
|
||||||
Promo: typeof import('./src/components/Promo/index.vue')['default']
|
Promo: typeof import('./src/components/Promo/index.vue')['default']
|
||||||
RandomIcon: typeof import('./src/components/RandomIcon.vue')['default']
|
RandomIcon: typeof import('./src/components/RandomIcon.vue')['default']
|
||||||
|
|
|
@ -21,8 +21,8 @@ const loadEnv = async () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
scene.value.environment = result.renderTarget.texture
|
scene.value.environment = result.renderTarget.texture
|
||||||
scene.value.background = result.renderTarget.texture
|
// scene.value.background = result.renderTarget.texture
|
||||||
scene.value.background.mapping = EquirectangularReflectionMapping
|
// scene.value.background.mapping = EquirectangularReflectionMapping
|
||||||
// scene.value.backgroundBlurriness = 0.15
|
// scene.value.backgroundBlurriness = 0.15
|
||||||
result.renderTarget.texture.dispose();
|
result.renderTarget.texture.dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,36 +4,18 @@ import {
|
||||||
Box3, Color, DoubleSide, Group, Mesh, MeshBasicMaterial,
|
Box3, Color, DoubleSide, Group, Mesh, MeshBasicMaterial,
|
||||||
PlaneGeometry, SpriteMaterial, TextureLoader, Vector2, Vector3,
|
PlaneGeometry, SpriteMaterial, TextureLoader, Vector2, Vector3,
|
||||||
} from 'three';
|
} from 'three';
|
||||||
// import { DepthOfField, EffectComposer, Pixelation } from '@tresjs/post-processing'
|
|
||||||
|
|
||||||
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
import { useTresContext, useSeek, useRenderLoop } from '@tresjs/core';
|
||||||
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
|
||||||
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
|
||||||
|
|
||||||
import { RGBShiftShader } from 'three/addons/shaders/RGBShiftShader.js';
|
|
||||||
import { DotScreenShader } from 'three/addons/shaders/DotScreenShader.js';
|
|
||||||
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
|
|
||||||
|
|
||||||
import '@tresjs/leches/styles'
|
|
||||||
|
|
||||||
import { useTresContext, useSeek, useRenderLoop, useLoop } from '@tresjs/core';
|
|
||||||
import { useGLTF } from '@tresjs/cientos'
|
import { useGLTF } from '@tresjs/cientos'
|
||||||
|
|
||||||
import Env from './env.vue'
|
import Env from './env.vue'
|
||||||
|
import PostProcess from './post_pocessing.vue'
|
||||||
|
|
||||||
import { IMAGE_URL, SERVER_URL, } from '../../constants'
|
import { IMAGE_URL, SERVER_URL, } from '../../constants'
|
||||||
import { usePromoSidebar } from '../../stores/promo_sidebar';
|
import { usePromoSidebar } from '../../stores/promo_sidebar';
|
||||||
import { usePromoScene } from '../../stores/promo_scene';
|
import { usePromoScene } from '../../stores/promo_scene';
|
||||||
|
|
||||||
const props = defineProps(['source', 'loaded', 'loaded_pan'])
|
const props = defineProps(['source', 'loaded', 'loaded_pan', 'clearColor'])
|
||||||
|
|
||||||
function shadows_and_pos(scene: any) {
|
|
||||||
scene.children.forEach((el: any) => {
|
|
||||||
// el.receiveShadow = true
|
|
||||||
// el.castShadow = true
|
|
||||||
shadows_and_pos(el)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const models = ref<model3DType[]>([])
|
const models = ref<model3DType[]>([])
|
||||||
const clickable = ref<clickableAreaType[]>([])
|
const clickable = ref<clickableAreaType[]>([])
|
||||||
|
@ -41,14 +23,14 @@ const clickable_items = ref<any[]>([])
|
||||||
const clickable_refs = ref<any[]>([])
|
const clickable_refs = ref<any[]>([])
|
||||||
const sidebar = usePromoSidebar();
|
const sidebar = usePromoSidebar();
|
||||||
const sidebar_scene = usePromoScene()
|
const sidebar_scene = usePromoScene()
|
||||||
const { renderer, controls, camera, scene, raycaster } = useTresContext()
|
const { controls, camera, scene, raycaster } = useTresContext()
|
||||||
const { seekByName, seekAllByName } = useSeek()
|
const { seekByName, seekAllByName } = useSeek()
|
||||||
const envVars = reactive({}) as { hdr_gainmap?: string, hdr_json?: string, hdr_webp?: string }
|
const envVars = reactive({}) as { hdr_gainmap?: string, hdr_json?: string, hdr_webp?: string }
|
||||||
|
const tiltShift = reactive({}) as { focus: number, aperture: number, maxblur: number }
|
||||||
|
|
||||||
// renderer.value.capabilities.maxTextures = 4
|
// renderer.value.capabilities.maxTextures = 4
|
||||||
// renderer.value.capabilities.maxTextureSize = 512
|
// renderer.value.capabilities.maxTextureSize = 512
|
||||||
// renderer.value.capabilities.precision = 'lowp'
|
// renderer.value.capabilities.precision = 'lowp'
|
||||||
let composer: any = null
|
|
||||||
|
|
||||||
const loadModels = async () => {
|
const loadModels = async () => {
|
||||||
const res = await fetch(`${SERVER_URL}/api/obj/scene/${props.source}`)
|
const res = await fetch(`${SERVER_URL}/api/obj/scene/${props.source}`)
|
||||||
|
@ -58,6 +40,10 @@ const loadModels = async () => {
|
||||||
envVars.hdr_json = raw_data.hdr_json ? `${IMAGE_URL}/${raw_data.hdr_json}` : undefined
|
envVars.hdr_json = raw_data.hdr_json ? `${IMAGE_URL}/${raw_data.hdr_json}` : undefined
|
||||||
envVars.hdr_webp = raw_data.hdr_webp ? `${IMAGE_URL}/${raw_data.hdr_webp}` : undefined
|
envVars.hdr_webp = raw_data.hdr_webp ? `${IMAGE_URL}/${raw_data.hdr_webp}` : undefined
|
||||||
|
|
||||||
|
tiltShift.focus = raw_data.max_distance * 0.33
|
||||||
|
tiltShift.aperture = 10
|
||||||
|
tiltShift.maxblur = 1
|
||||||
|
|
||||||
const data = raw_data.elements
|
const data = raw_data.elements
|
||||||
if (!controls.value) return;
|
if (!controls.value) return;
|
||||||
|
|
||||||
|
@ -77,7 +63,6 @@ const loadModels = async () => {
|
||||||
|
|
||||||
item.modelUrl = `${IMAGE_URL}/${element.model_file}`
|
item.modelUrl = `${IMAGE_URL}/${element.model_file}`
|
||||||
let { scene: loaded_scene } = await useGLTF(item.modelUrl)
|
let { scene: loaded_scene } = await useGLTF(item.modelUrl)
|
||||||
shadows_and_pos(loaded_scene)
|
|
||||||
item.modelFile = loaded_scene
|
item.modelFile = loaded_scene
|
||||||
item.name = element.name
|
item.name = element.name
|
||||||
|
|
||||||
|
@ -93,7 +78,6 @@ const loadModels = async () => {
|
||||||
const element = clickable.value[index];
|
const element = clickable.value[index];
|
||||||
const find_element = seekByName(scene.value, element.object_name)
|
const find_element = seekByName(scene.value, element.object_name)
|
||||||
if (!find_element) continue
|
if (!find_element) continue
|
||||||
// const res_array = (find_element as Group).isGroup ? find_element?.children : [find_element]
|
|
||||||
if (find_element && !(find_element as Group).isGroup) {
|
if (find_element && !(find_element as Group).isGroup) {
|
||||||
const world_position = new Vector3();
|
const world_position = new Vector3();
|
||||||
((find_element as Mesh).geometry.boundingBox as any).getCenter(world_position);
|
((find_element as Mesh).geometry.boundingBox as any).getCenter(world_position);
|
||||||
|
@ -114,9 +98,7 @@ const loadModels = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const point = new Mesh(plane, mesh_material);
|
const point = new Mesh(plane, mesh_material);
|
||||||
// const point = new Sprite(sprite_material)
|
|
||||||
point.position.set(world_position.x, p * 3, world_position.z)
|
point.position.set(world_position.x, p * 3, world_position.z)
|
||||||
// point.scale.set(p, p, 1)
|
|
||||||
point.name = `${element.id}_clickable`
|
point.name = `${element.id}_clickable`
|
||||||
point.renderOrder = 10
|
point.renderOrder = 10
|
||||||
|
|
||||||
|
@ -139,36 +121,17 @@ const loadModels = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
controls.value.enabled = true;
|
controls.value.enabled = true;
|
||||||
props.loaded()
|
props.loaded(false)
|
||||||
|
|
||||||
composer = new EffectComposer(renderer.value);
|
|
||||||
composer.addPass(new RenderPass(scene.value, camera.value));
|
|
||||||
|
|
||||||
const effect1 = new ShaderPass(DotScreenShader);
|
|
||||||
effect1.uniforms['scale'].value = 40;
|
|
||||||
composer.addPass(effect1);
|
|
||||||
function animate() {
|
|
||||||
requestAnimationFrame(animate);
|
|
||||||
composer.render();
|
|
||||||
}
|
|
||||||
// animate()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { onLoop } = useRenderLoop()
|
const { onLoop } = useRenderLoop()
|
||||||
onLoop(() => {
|
onLoop(() => {
|
||||||
clickable_refs.value.map(el => {
|
clickable_refs.value.map(el => {
|
||||||
// el.quaternion.copy(camera.value?.quaternion);
|
|
||||||
if (el.value[0] && typeof el.value[0].lookAt == 'function') {
|
if (el.value[0] && typeof el.value[0].lookAt == 'function') {
|
||||||
el.value[0].lookAt(camera.value?.position)
|
el.value[0].lookAt(camera.value?.position)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const { onAfterRender } = useLoop()
|
|
||||||
onAfterRender(() => {
|
|
||||||
if (composer) {
|
|
||||||
composer.render()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const openSidebar = (id: number) => {
|
const openSidebar = (id: number) => {
|
||||||
const target = clickable.value.find(el => el.id == id)
|
const target = clickable.value.find(el => el.id == id)
|
||||||
|
@ -233,6 +196,7 @@ watch(() => sidebar_scene.list, () => {
|
||||||
<template>
|
<template>
|
||||||
<TresGroup name="loaded">
|
<TresGroup name="loaded">
|
||||||
<Env v-bind="envVars" />
|
<Env v-bind="envVars" />
|
||||||
|
<PostProcess :tiltShift="tiltShift" :clearColor="props.clearColor" />
|
||||||
<template v-for="item in models">
|
<template v-for="item in models">
|
||||||
<TresGroup :name="item.name">
|
<TresGroup :name="item.name">
|
||||||
<TresObject3D v-bind="item.modelFile.clone()" />
|
<TresObject3D v-bind="item.modelFile.clone()" />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref, watch, computed } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import { RouterLink, useRoute } from 'vue-router';
|
import { RouterLink, useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@ const cameraPosition = ref([1, 1, 1]) as unknown as Ref<Vector3>
|
||||||
|
|
||||||
const controlsState = reactive({
|
const controlsState = reactive({
|
||||||
enableDamping: false,
|
enableDamping: false,
|
||||||
maxPolarAngle: (Math.PI / 2) - 0.05,
|
maxPolarAngle: (Math.PI / 2) - 0.07,
|
||||||
minAzimuthAngle: (Math.PI / 2) - 0.02,
|
minAzimuthAngle: (Math.PI / 2) - 0.07,
|
||||||
})
|
})
|
||||||
const models_loading = ref(false)
|
const models_loading = ref(true)
|
||||||
const set_model_load_status = () => {
|
const set_model_load_status = (status: boolean) => {
|
||||||
models_loading.value = !models_loading.value
|
models_loading.value = status
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
@ -49,23 +49,26 @@ watch(() => route.params.target, () => {
|
||||||
if (route.params.target) t = route.params.target.toString() + '/'
|
if (route.params.target) t = route.params.target.toString() + '/'
|
||||||
if (source.value !== t) {
|
if (source.value !== t) {
|
||||||
source.value = t
|
source.value = t
|
||||||
models_loading.value = false
|
models_loading.value = true
|
||||||
sidebar.close()
|
sidebar.close()
|
||||||
}
|
}
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
|
const clearColor = 'steelBlue'
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div :class="[{ 'loading': !models_loading }, 'canvas-wrapper']">
|
<div :class="[{ 'loading': models_loading }, 'canvas-wrapper']">
|
||||||
<TresCanvas window-size :alpha="false" power-preference="high-performance">
|
<TresCanvas window-size :alpha="false" power-preference="high-performance" :clear-color="clearColor">
|
||||||
<TresPerspectiveCamera :position="cameraPosition" ref="camera" />
|
<TresPerspectiveCamera :position="cameraPosition" ref="camera" />
|
||||||
<OrbitControls v-bind="controlsState" @change="onChange" make-default />
|
<OrbitControls v-bind="controlsState" @change="onChange" make-default />
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<LoadModels :source="source" :loaded="set_model_load_status" :loaded_pan="loadedPan" />
|
<LoadModels :source="source" :loaded="set_model_load_status" :loaded_pan="loadedPan" :clear-color="clearColor" />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<TresMesh :position-y="-1" :rotate-x="-Math.PI / 2" receive-shadow name="ground" v-if="false">
|
<TresMesh :position-y="-1" :rotate-x="-Math.PI / 2" receive-shadow>
|
||||||
<TresPlaneGeometry :args="[200, 200]" />
|
<TresPlaneGeometry :args="[2000, 2000]" />
|
||||||
<TresShadowMaterial :opacity="0.2" />
|
<!-- <TresShadowMaterial :opacity="0.2" /> -->
|
||||||
|
<TresMeshStandardMaterial :color="clearColor" />
|
||||||
</TresMesh>
|
</TresMesh>
|
||||||
</TresCanvas>
|
</TresCanvas>
|
||||||
<div class="homelink">
|
<div class="homelink">
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
||||||
|
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
||||||
|
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
||||||
|
|
||||||
|
import { BokehPass } from 'three/addons/postprocessing/BokehPass.js';
|
||||||
|
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
|
||||||
|
|
||||||
|
import { useTresContext, useLoop } from '@tresjs/core';
|
||||||
|
import { watch } from 'vue';
|
||||||
|
import { Fog, FogExp2 } from 'three';
|
||||||
|
|
||||||
|
const { renderer, camera, scene } = useTresContext()
|
||||||
|
|
||||||
|
const composer = new EffectComposer(renderer.value);
|
||||||
|
|
||||||
|
const props = defineProps(['tiltShift', 'clearColor'])
|
||||||
|
const k = { start: 0.25, end: 3 }
|
||||||
|
|
||||||
|
if (camera.value) {
|
||||||
|
const renderPass = new RenderPass(scene.value, camera.value);
|
||||||
|
|
||||||
|
const bokehPass = new BokehPass(scene.value, camera.value, {
|
||||||
|
focus: props.tiltShift.focus,
|
||||||
|
aperture: (props.tiltShift.aperture) * 0.00001,
|
||||||
|
maxblur: (props.tiltShift.maxblur) * 0.01
|
||||||
|
});
|
||||||
|
|
||||||
|
const outputPass = new OutputPass();
|
||||||
|
composer.addPass(renderPass);
|
||||||
|
composer.addPass(bokehPass);
|
||||||
|
composer.addPass(outputPass);
|
||||||
|
|
||||||
|
// scene.value.fog = new FogExp2(0xff0000, 0.005)
|
||||||
|
scene.value.fog = new Fog(props.clearColor, props.tiltShift.focus * k.start, props.tiltShift.focus * k.end)
|
||||||
|
}
|
||||||
|
const { onAfterRender } = useLoop()
|
||||||
|
onAfterRender(() => {
|
||||||
|
composer.render()
|
||||||
|
})
|
||||||
|
watch(props.tiltShift, () => {
|
||||||
|
if (camera.value) {
|
||||||
|
const args = {
|
||||||
|
focus: props.tiltShift.focus,
|
||||||
|
aperture: props.tiltShift.aperture * 0.00001,
|
||||||
|
maxblur: props.tiltShift.maxblur * 0.01
|
||||||
|
}
|
||||||
|
const bokehPass = new BokehPass(scene.value, camera.value, args);
|
||||||
|
composer.passes = []
|
||||||
|
const renderPass = new RenderPass(scene.value, camera.value);
|
||||||
|
const outputPass = new OutputPass();
|
||||||
|
composer.addPass(renderPass);
|
||||||
|
composer.addPass(bokehPass);
|
||||||
|
composer.addPass(outputPass);
|
||||||
|
|
||||||
|
scene.value.fog = new Fog(props.clearColor, props.tiltShift.focus * k.start, props.tiltShift.focus * k.end)
|
||||||
|
}
|
||||||
|
}, { deep: true })
|
||||||
|
</script>
|
||||||
|
<template></template>
|
|
@ -59,7 +59,7 @@ interface PromoScene {
|
||||||
id: number
|
id: number
|
||||||
model_file: string
|
model_file: string
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description?: string
|
||||||
parent?: number
|
parent?: number
|
||||||
is_enabled: boolean
|
is_enabled: boolean
|
||||||
}
|
}
|
Loading…
Reference in New Issue