Merge branch 'bx-696-startproject' of https://git.svs-tech.pro/ksenia_mikhailova/mns-mini-zabor into bx-696-startproject
34
app.vue
|
@ -34,16 +34,13 @@ const roubleSign = new Intl.NumberFormat('ru-RU', {
|
|||
|
||||
const aboutText = computed(() => marked.parse(about?.content || ''))
|
||||
const deliveryText = computed(() => delivery?.content.split('[col]').map(el => marked.parse(el || '')))
|
||||
const advantagesText = computed(() =>
|
||||
advantages?.content.split('[col]').map(el => {
|
||||
let c = el || ''
|
||||
Object.entries(calculatorData.value || {}).map(item => {
|
||||
c = c.replaceAll(`[${item[0]}]`, roubleSign.format(item[1]))
|
||||
})
|
||||
return marked.parse(c)
|
||||
}
|
||||
)
|
||||
)
|
||||
const advantagesText = computed(() => {
|
||||
let c = advantages?.content || ''
|
||||
Object.entries(calculatorData.value || {}).map(item => {
|
||||
c = c.replaceAll(`[${item[0]}]`, roubleSign.format(item[1]))
|
||||
})
|
||||
return marked.parse(c)
|
||||
})
|
||||
|
||||
const { data: footerData } = await useFetch<ApiFooterType[]>(`${apiBase}/footer/?ordering=small_text`)
|
||||
const { data: social_networkData } = await useFetch<ApiSocial_networkType[]>(`${apiBase}/social_network/`)
|
||||
|
@ -117,15 +114,12 @@ const { scrollToAnchor, scrollToTop } = useAnchorScroll({
|
|||
</div>
|
||||
</div>
|
||||
<div class="siteblock bg-white">
|
||||
<ExpDiagram />
|
||||
</div>
|
||||
<div class="siteblock bg-white" :id="advantages?.slug" v-if="advantagesText">
|
||||
<div class="container">
|
||||
<div class="prose col-span-12 xl:col-span-6">
|
||||
<span v-html="advantagesText[0]"></span>
|
||||
<div class="container gap-4">
|
||||
<div class="col-span-full xl:col-span-8">
|
||||
<ExpDiagram />
|
||||
</div>
|
||||
<div class="prose col-span-12 xl:col-span-6">
|
||||
<span v-html="advantagesText[1]"></span>
|
||||
<div class="col-span-full xl:col-span-4 prose">
|
||||
<span v-html="advantagesText"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -135,7 +129,9 @@ const { scrollToAnchor, scrollToTop } = useAnchorScroll({
|
|||
</div>
|
||||
<div class="siteblock siteblock_calc bg-white">
|
||||
<CalcValues />
|
||||
<CalcModels />
|
||||
<Suspense>
|
||||
<CalcModels />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div class="siteblock bg-white" :id="delivery?.slug" v-if="deliveryText">
|
||||
<div class="container">
|
||||
|
|
|
@ -74,11 +74,7 @@ a[href^="#"] {
|
|||
@apply py-10;
|
||||
|
||||
&_imgbg {
|
||||
@apply py-0 bg-no-repeat bg-cover bg-bottom;
|
||||
|
||||
img {
|
||||
max-height: 50vh;
|
||||
}
|
||||
@apply py-0 bg-no-repeat bg-cover bg-bottom h-[50vh];
|
||||
}
|
||||
|
||||
&_calc {
|
||||
|
|
|
@ -1,82 +1,96 @@
|
|||
<script setup lang="ts">
|
||||
import { TresCanvas } from '@tresjs/core'
|
||||
import { OrbitControls, Environment, vLightHelper } from '@tresjs/cientos'
|
||||
import { FrontSide, RepeatWrapping } from 'three';
|
||||
import { TresCanvas, useTexture } from '@tresjs/core'
|
||||
import { OrbitControls, Environment, useGLTF } from '@tresjs/cientos'
|
||||
|
||||
const section_count = useState<number>('section_count')
|
||||
const fence_section = useState<number>('fence_section')
|
||||
|
||||
const controlsState = reactive({
|
||||
minDistance: 5,
|
||||
maxDistance: 12,
|
||||
enablePan: false,
|
||||
// enableZoom: false,
|
||||
maxPolarAngle: (Math.PI / 2) - 0.2,
|
||||
// maxZoom: 2,
|
||||
// minZoom: 1,
|
||||
})
|
||||
const cameraStat = reactive({
|
||||
position: [-4, 2, 8],
|
||||
aspect: 1920 / 600,
|
||||
fov: 40,
|
||||
})
|
||||
|
||||
const pointLight = ref()
|
||||
|
||||
const groundMaterial = ref({
|
||||
color: "#555",
|
||||
roughness: 0.25,
|
||||
metalness: 0,
|
||||
side: FrontSide
|
||||
})
|
||||
const loadAll = async () => {
|
||||
const { scene: light } = await useGLTF('/models_light/zabor_so_svetom.glb')
|
||||
pointLight.value = light.children[2]
|
||||
pointLight.value.color = '#f0dea9'
|
||||
pointLight.value.shadow.camera.near = 50
|
||||
pointLight.value.shadow.bias = -0.001
|
||||
|
||||
const pbrTexture = await useTexture({
|
||||
map: '/texture/Grass004_2K-PNG/Grass004_2K-PNG_Color.png',
|
||||
displacementMap: '/texture/Grass004_2K-PNG/Grass004_2K-PNG_Displacement.png',
|
||||
roughnessMap: '/texture/Grass004_2K-PNG/Grass004_2K-PNG_Roughness.png',
|
||||
normalMap: '/texture/Grass004_2K-PNG/Grass004_2K-PNG_NormalDX.png',
|
||||
aoMap: '/texture/Grass004_2K-PNG/Grass004_2K-PNG_AmbientOcclusion.png',
|
||||
})
|
||||
const repeat = 10
|
||||
for (const key in pbrTexture) {
|
||||
if (Object.prototype.hasOwnProperty.call(pbrTexture, key)) {
|
||||
const key_p = key as keyof typeof pbrTexture
|
||||
const element = pbrTexture[key_p]
|
||||
if (element && element.wrapS) {
|
||||
element.wrapS = RepeatWrapping
|
||||
element.wrapT = RepeatWrapping
|
||||
element.repeat.x = repeat
|
||||
element.repeat.y = repeat
|
||||
element.flipY = false
|
||||
}
|
||||
}
|
||||
}
|
||||
groundMaterial.value = Object.assign(groundMaterial.value, {
|
||||
map: pbrTexture.map,
|
||||
displacementMap: pbrTexture.displacementMap,
|
||||
normalMap: pbrTexture.normalMap,
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
cameraStat.aspect = window.innerWidth / 600
|
||||
})
|
||||
const spot = reactive({
|
||||
x: 10, y: 10, z: 10, intensity: 10, distance: 10, color: 'red'
|
||||
})
|
||||
const directional = reactive({
|
||||
x: 20, y: 10, z: 10, intensity: 10, distance: 10, color: 'green'
|
||||
})
|
||||
const point = reactive({
|
||||
x: 30, y: 10, z: 10, intensity: 10, distance: 10, color: 'blue'
|
||||
cameraStat.aspect = window.innerWidth / (window.innerHeight * 0.5)
|
||||
loadAll()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="container min-w-full relative" v-if="false">
|
||||
<div>
|
||||
<h2>spot</h2>
|
||||
<template v-for="(label, key) in spot">
|
||||
<label :for="key">{{ key }}</label>
|
||||
<input :id="key" :type="key == 'color' ? 'text' : 'number'" v-model="spot[key]" style="width: 100px" />
|
||||
</template>
|
||||
<h2>directional</h2>
|
||||
<template v-for="(label, key) in directional">
|
||||
<label :for="key">{{ key }}</label>
|
||||
<input :id="key" :type="key == 'color' ? 'text' : 'number'" v-model="directional[key]"
|
||||
style="width: 100px" />
|
||||
</template>
|
||||
<h2>point</h2>
|
||||
<template v-for="(label, key) in point">
|
||||
<label :for="key">{{ key }}</label>
|
||||
<input :id="key" :type="key == 'color' ? 'text' : 'number'" v-model="point[key]" style="width: 100px" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container min-w-full relative">
|
||||
<div class="container min-w-full relative h-[50vh]">
|
||||
<ClientOnly fallback-tag="div" fallback="Загрузка 3D модели">
|
||||
<Loader />
|
||||
<TresCanvas shadows>
|
||||
<TresPerspectiveCamera v-bind="cameraStat" />
|
||||
<OrbitControls v-bind="controlsState" make-default />
|
||||
<Suspense>
|
||||
<Suspense v-if="false">
|
||||
<Environment files='/hdrmaps/kloppenheim_06_4k.hdr' :background="true" />
|
||||
</Suspense>
|
||||
<Suspense>
|
||||
<ModelParametric />
|
||||
</Suspense>
|
||||
<template v-if="false">
|
||||
<TresSpotLight v-bind="spot" :position="[spot.x, spot.y, spot.z]" cast-shadow v-light-helper />
|
||||
<TresDirectionalLight v-bind="directional" :position="[directional.x, directional.y, directional.z]"
|
||||
cast-shadow v-light-helper />
|
||||
<TresPointLight v-bind="point" :position="[point.x, point.y, point.z]" cast-shadow v-light-helper />
|
||||
<TresAmbientLight />
|
||||
<TresGroup :position-x="Math.min(section_count, 20) * fence_section * -1" :position-y="-3">
|
||||
<Suspense>
|
||||
<ModelParametric />
|
||||
</Suspense>
|
||||
</TresGroup>
|
||||
<TresMesh receive-shadow :position-y="-3.65" name="ground">
|
||||
<TresCircleGeometry :args="[100, 32]" :rotate-x="-Math.PI * 0.5" />
|
||||
<TresMeshStandardMaterial v-bind="groundMaterial" />
|
||||
</TresMesh>
|
||||
<template v-if="pointLight">
|
||||
<TresPointLight v-bind="pointLight" :intensity="pointLight.intensity * 0.5"
|
||||
:position="Object.values(pointLight.position).map((el: any) => el * 3)" cast-shadow />
|
||||
</template>
|
||||
|
||||
<TresAmbientLight color="rgb(191,231,255)" :intensity="5" />
|
||||
</TresCanvas>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
height: 600px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</template>
|
|
@ -2,25 +2,26 @@
|
|||
import { getColorNameFromRal } from '@/components/ral'
|
||||
import type { ralTypes } from '@/components/ral'
|
||||
|
||||
const lamelles_count = useState('lamelles_count', () => 8)
|
||||
const lamelles_count = useState('lamelles_count', () => 14)
|
||||
const fence_section = useState<number>('fence_section', () => 2000 * 0.001)
|
||||
const remove_pillar = useState<boolean>('remove_pillar', () => false)
|
||||
const pillar_color = useState<ralTypes>('pillar_color', () => '3009')
|
||||
const lamelle_color = useState<ralTypes>('lamelle_color', () => '3004')
|
||||
const section_count = useState('section_count', () => 1)
|
||||
const section_count = useState('section_count', () => 10)
|
||||
const extra_section = useState('extra_section', () => 0)
|
||||
const total_length = useState('total_length', () => 2000 * 0.001 * 2)
|
||||
const total_length = useState('total_length', () => (2000 * 8 - 100) * 0.001)
|
||||
const min_length = useState('min_length', () => 1000)
|
||||
|
||||
const parametric = {
|
||||
length: {
|
||||
min: 1000,
|
||||
min: min_length.value,
|
||||
max: 2400,
|
||||
step: 1,
|
||||
},
|
||||
total_length: {
|
||||
min: 1,
|
||||
min: min_length.value * 0.001,
|
||||
max: undefined,
|
||||
step: 0.1,
|
||||
step: 0.5,
|
||||
},
|
||||
height: {
|
||||
min: 675,
|
||||
|
@ -32,9 +33,9 @@ const form_state = reactive({
|
|||
length: fence_section.value * 1000,
|
||||
fence_length: 100,
|
||||
height: 100 + lamelles_count.value * parametric.height.step,
|
||||
total_length: fence_section.value * 2,
|
||||
total_length: total_length.value,
|
||||
total_length_mm: fence_section.value * 1000,
|
||||
full_sections: 1,
|
||||
full_sections: section_count.value,
|
||||
extra_section: 0,
|
||||
auto_length: false,
|
||||
remove_pillar: false
|
||||
|
@ -92,7 +93,7 @@ const changeParametres = () => {
|
|||
form_state.total_length = parametric.total_length.min
|
||||
form_state.length = parametric.length.min
|
||||
}
|
||||
}, 300)
|
||||
}, 600)
|
||||
|
||||
total_length.value = form_state.total_length
|
||||
lamelles_count.value = lamelles
|
||||
|
@ -120,7 +121,7 @@ const toggleModal = () => {
|
|||
}
|
||||
const plurals = {
|
||||
lamelle: { one: 'ламель', few: 'ламели', many: 'ламелей' },
|
||||
fence: { one: 'cстолб', few: 'столба', many: 'столбов' },
|
||||
fence: { one: 'cтолб', few: 'столба', many: 'столбов' },
|
||||
section: { one: 'секция', few: 'секции', many: 'секций' },
|
||||
}
|
||||
</script>
|
||||
|
@ -164,25 +165,25 @@ const plurals = {
|
|||
<label for="lamelle_color">Цвет ламелей</label>
|
||||
<input id="lamelle_color" type="text" :value="getColorNameFromRal(lamelle_color)"
|
||||
class="w-60" disabled />
|
||||
<ColorPicker :cb="setLamelleColor" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<template v-for="item in predefLamelleColors">
|
||||
<ColorPicker :color="item" :cb="setLamelleColor" :open="false"
|
||||
:active="lamelle_color == item" />
|
||||
</template>
|
||||
<ColorPicker :cb="setLamelleColor" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label for="pillar_color">Цвет столба</label>
|
||||
<input id="pillar_color" type="text" :value="getColorNameFromRal(pillar_color)" class="w-60"
|
||||
disabled />
|
||||
<ColorPicker :cb="setPillarColor" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<template v-for="item in predefPillarColors">
|
||||
<ColorPicker :color="item" :cb="setPillarColor" :open="false"
|
||||
:active="pillar_color == item" />
|
||||
</template>
|
||||
<ColorPicker :cb="setPillarColor" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,19 +9,6 @@ const controlsState = reactive({
|
|||
// enableZoom: false,
|
||||
maxPolarAngle: (Math.PI / 2) - 0.2,
|
||||
})
|
||||
const container = ref()
|
||||
const koef = ref()
|
||||
const scrollBlock = (e: Event) => {
|
||||
const { top, bottom, height } = container.value.getBoundingClientRect();
|
||||
const { innerHeight } = window;
|
||||
const partiallyVisible = (top > 0 && top < innerHeight) ||
|
||||
(bottom > 0 && bottom < innerHeight)
|
||||
const visibleHeight = innerHeight - top
|
||||
const h = height * 1.5
|
||||
if (partiallyVisible && visibleHeight < h) {
|
||||
koef.value = visibleHeight / h
|
||||
}
|
||||
}
|
||||
const targetExplosion = useState('targetExplosion', () => {
|
||||
const k = 1.5
|
||||
return {
|
||||
|
@ -35,15 +22,9 @@ const targetExplosion = useState('targetExplosion', () => {
|
|||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="container min-w-full" ref="container">
|
||||
<div class="h-96">
|
||||
<ClientOnly fallback-tag="div" fallback="Загрузка 3D модели">
|
||||
<template v-for="(value, key) in targetExplosion" v-if="false">
|
||||
<div>
|
||||
<label for="key">{{ key }}</label>
|
||||
<input type="number" v-for="(item, n) in value" v-model="targetExplosion[key][n]" step="0.25">
|
||||
</div>
|
||||
</template>
|
||||
<TresCanvas preset="realistic">
|
||||
<TresCanvas preset="realistic" heoght="600">
|
||||
<TresPerspectiveCamera :position="[-7, 2, 4]" />
|
||||
<OrbitControls v-bind="controlsState" make-default />
|
||||
<Suspense>
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { getColorHexFromRal } from '@/components/ral'
|
||||
import type { ralTypes } from '@/components/ral'
|
||||
import { CanvasTexture } from 'three';
|
||||
|
||||
const props = defineProps(['index', 'models'])
|
||||
|
||||
const lamelles_count = useState<number>('lamelles_count')
|
||||
const fence_section = useState<number>('fence_section')
|
||||
const section_count = useState<number>('section_count')
|
||||
const extra_section = useState<number>('extra_section')
|
||||
const pillar_color = useState<ralTypes>('pillar_color')
|
||||
const lamelle_color = useState<ralTypes>('lamelle_color')
|
||||
const remove_pillar = useState<boolean>('remove_pillar')
|
||||
|
@ -14,11 +17,11 @@ const lSize = 0.115
|
|||
const bSize = 0.0235
|
||||
const pillar_size = 80 * 0.001
|
||||
|
||||
const pillar_one_pos = ref(fence_section.value * -0.5 - 0.01)
|
||||
const pillar_one_pos = ref(fence_section.value * -0.5 - 0.015)
|
||||
const pillar_two_pos = ref(fence_section.value * 0.5 + pillar_size + bSize - 0.01)
|
||||
|
||||
watch([fence_section, lamelles_count], () => {
|
||||
pillar_one_pos.value = fence_section.value * -0.5 - 0.01
|
||||
pillar_one_pos.value = fence_section.value * -0.5 - 0.015
|
||||
pillar_two_pos.value = fence_section.value * 0.5 + pillar_size + bSize - 0.01
|
||||
})
|
||||
const scale_koef = 2.5
|
||||
|
@ -26,13 +29,8 @@ const show_pillar_one = ref(props.index == 1)
|
|||
const show_pillar_two = ref(true)
|
||||
|
||||
const make_translate_to_section = () => {
|
||||
let r = ((props.index - 1) / 2) * (fence_section.value + pillar_size + bSize) * scale_koef
|
||||
if (props.index % 2 == 0) {
|
||||
show_pillar_two.value = false
|
||||
show_pillar_one.value = true
|
||||
r += (fence_section.value * 0.5 + bSize) * scale_koef
|
||||
return -1 * r
|
||||
}
|
||||
const one_s = (fence_section.value + pillar_size + bSize)
|
||||
let r = (props.index - 1) * one_s * scale_koef
|
||||
return r
|
||||
}
|
||||
const translate_to_section = ref(make_translate_to_section())
|
||||
|
@ -40,10 +38,51 @@ const translate_to_section = ref(make_translate_to_section())
|
|||
watch(fence_section, () => {
|
||||
translate_to_section.value = make_translate_to_section()
|
||||
})
|
||||
|
||||
const s = 512
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = s
|
||||
canvas.height = s
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
|
||||
ctx.fillStyle = "red"
|
||||
ctx.font = "512px serif"
|
||||
ctx.textAlign = "center"
|
||||
ctx.textBaseline = 'middle'
|
||||
ctx.fillText(props.index, s * 0.5, s * 0.5)
|
||||
|
||||
const textures: any[] = []
|
||||
for (let index = 0; index < lamelles_count.value; index++) {
|
||||
const element = document.createElement('canvas')
|
||||
element.width = s
|
||||
element.height = s / lamelles_count.value
|
||||
const e_ctx = element.getContext('2d') as CanvasRenderingContext2D
|
||||
e_ctx.drawImage(canvas,
|
||||
0, (s / lamelles_count.value) * index, s, s / lamelles_count.value,
|
||||
0, 0, s, s / lamelles_count.value
|
||||
);
|
||||
textures.push(new CanvasTexture(element))
|
||||
}
|
||||
const extra = ref((extra_section && props.index == (section_count.value + 1)) ? extra_section.value * 0.001 : false)
|
||||
if (extra.value) {
|
||||
pillar_two_pos.value = extra.value * 0.5 + pillar_size + bSize - 0.01
|
||||
}
|
||||
watch([extra_section, section_count], () => {
|
||||
extra.value = (extra_section && props.index == (section_count.value + 1)) ? extra_section.value * 0.001 : false
|
||||
if (extra_section && props.index == (section_count.value + 1)) {
|
||||
// pillar_one_pos.value = extra_section.value * -0.5 - 0.015
|
||||
pillar_two_pos.value = extra.value * 0.5 + pillar_size + bSize - 0.01
|
||||
} else {
|
||||
// pillar_one_pos.value = fence_section.value * -0.5 - 0.015
|
||||
pillar_two_pos.value = fence_section.value * 0.5 + pillar_size + bSize - 0.01
|
||||
}
|
||||
})
|
||||
console.log({ pillar_size, fence_section: fence_section.value })
|
||||
</script>
|
||||
<template>
|
||||
<TresGroup :scale="scale_koef" :position-x="translate_to_section" :name="`fence ${index}`">
|
||||
<TresGroup name="pillar_one" v-if="!remove_pillar && show_pillar_one" :position-x="pillar_one_pos" :position-z="0">
|
||||
<TresGroup :scale="scale_koef" :position-x="translate_to_section" :name="`fence ${index}`"
|
||||
:position-y="extra ? 1 : 0">
|
||||
<TresGroup name="pillar_one" v-if="!remove_pillar && show_pillar_one" :position-x="pillar_one_pos"
|
||||
:position-z="0">
|
||||
<TresGroup :position-y="(lSize * -0.5)" :scale="[1, 0.5, 1]">
|
||||
<ModelItem :model="props.models.fence" :color="getColorHexFromRal(pillar_color)" />
|
||||
</TresGroup>
|
||||
|
@ -57,7 +96,8 @@ watch(fence_section, () => {
|
|||
</TresGroup>
|
||||
</TresGroup>
|
||||
|
||||
<TresGroup name="pillar_two" v-if="!remove_pillar && show_pillar_two" :position-x="pillar_two_pos" :position-z="0">
|
||||
<TresGroup name="pillar_two" v-if="!remove_pillar && show_pillar_two" :position-x="pillar_two_pos"
|
||||
:position-z="0">
|
||||
<TresGroup :position-y="(lSize * -0.5)" :scale="[-1, 0.5, 1]">
|
||||
<ModelItem :model="props.models.fence" :color="getColorHexFromRal(pillar_color)" />
|
||||
</TresGroup>
|
||||
|
@ -73,8 +113,9 @@ watch(fence_section, () => {
|
|||
|
||||
<TresGroup name="lamelles">
|
||||
<template v-for="(n, i) in lamelles_count">
|
||||
<TresGroup :position="[pillar_size * 0.5, (lSize * i), 0.02]" :scale-x="fence_section * 10">
|
||||
<ModelItem :model="props.models.lamelle" :color="getColorHexFromRal(lamelle_color)" />
|
||||
<TresGroup :position="[pillar_size * 0.5, (lSize * i), 0.02]" :scale-x="(extra || fence_section) * 10">
|
||||
<ModelItem :model="props.models.lamelle" :color="getColorHexFromRal(lamelle_color)"
|
||||
:map="textures[textures.length - 1 - i]" />
|
||||
</TresGroup>
|
||||
</template>
|
||||
</TresGroup>
|
||||
|
@ -93,7 +134,7 @@ watch(fence_section, () => {
|
|||
</TresGroup>
|
||||
</template>
|
||||
</TresGroup>
|
||||
<TresGroup name="top_section" :scale-x="fence_section * 10"
|
||||
<TresGroup name="top_section" :scale-x="(extra || fence_section) * 10"
|
||||
:position="[pillar_size * 0.5, lamelles_count * lSize, 0]">
|
||||
<ModelItem :model="props.models.top" :color="getColorHexFromRal(pillar_color)" />
|
||||
</TresGroup>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useGLTF } from '@tresjs/cientos'
|
||||
import { Box3, Color, MeshStandardMaterial, Vector3 } from 'three';
|
||||
const props = defineProps(['modelUrl', 'model', 'position', 'refPosition', 'removePos', 'target', 'color'])
|
||||
import { Box3, Color, DoubleSide, MeshStandardMaterial, Vector3 } from 'three';
|
||||
const props = defineProps(['modelUrl', 'model', 'position', 'refPosition', 'removePos', 'target', 'color', 'map'])
|
||||
|
||||
let scene
|
||||
if (props.modelUrl) {
|
||||
|
@ -21,8 +21,8 @@ box.getSize(size)
|
|||
|
||||
const getMaterial = () => {
|
||||
return new MeshStandardMaterial({
|
||||
color: props.color ? new Color(props.color) : new Color('#9c9c9c'),
|
||||
roughness: 0.3,
|
||||
color: new Color(props.color || '#9c9c9c'),
|
||||
roughness: 0.2,
|
||||
metalness: 0.5,
|
||||
})
|
||||
}
|
||||
|
@ -102,6 +102,10 @@ watch(targetExplosion, () => {
|
|||
<TresGroup :position="props.refPosition ? targetExplosion[props.refPosition] : (props.position || [0, 0, 0])"
|
||||
ref="model">
|
||||
<primitive :object="scene.children[0]" />
|
||||
<TresMesh v-if="props.map" :cast-shadow="false" :receive-shadow="false">
|
||||
<TresPlaneGeometry :args="[size.x, size.y]" />
|
||||
<TresMeshPhongMaterial :map="props.map" :transparent="true" :opacity="0.5" :side="DoubleSide" />
|
||||
</TresMesh>
|
||||
</TresGroup>
|
||||
</Suspense>
|
||||
</template>
|
|
@ -1,111 +1,54 @@
|
|||
<script setup lang="ts">
|
||||
import { ReinhardToneMapping, PCFShadowMap, RepeatWrapping, Color, DataTexture, RGBAFormat } from 'three';
|
||||
import { useTexture } from '@tresjs/core'
|
||||
import { useGLTF } from '@tresjs/cientos'
|
||||
const section_count = useState('section_count')
|
||||
import {
|
||||
ReinhardToneMapping, PCFSoftShadowMap,
|
||||
PMREMGenerator, Euler,
|
||||
} from 'three';
|
||||
import { EXRLoader } from 'three/examples/jsm/Addons.js';
|
||||
import { useGLTF, } from '@tresjs/cientos'
|
||||
|
||||
const section_count = useState<number>('section_count')
|
||||
const extra_section = useState<number>('extra_section')
|
||||
|
||||
const { scene, renderer, camera } = useTresContext()
|
||||
renderer.value.toneMapping = ReinhardToneMapping
|
||||
|
||||
renderer.value.shadowMap.enabled = true
|
||||
renderer.value.shadowMap.type = PCFShadowMap
|
||||
renderer.value.shadowMap.type = PCFSoftShadowMap
|
||||
|
||||
const pbrTexture = await useTexture({
|
||||
map: '/texture/Grass001_4K-JPG/Grass001_4K-JPG_Color.jpg',
|
||||
// displacementMap: '/texture/Ground039_4K-JPG_Displacement.jpg',
|
||||
roughnessMap: '/texture/Grass001_4K-JPG/Grass001_4K-JPG_Roughness.jpg',
|
||||
normalMap: '/texture/Grass001_4K-JPG/Grass001_4K-JPG_NormalGL.jpg',
|
||||
aoMap: '/texture/Grass001_4K-JPG/Grass001_4K-JPG_AmbientOcclusion.jpg',
|
||||
// metalnessMap: '/texture/Ground039_4K-JPG_Color.jpg',
|
||||
// matcap: '/textures/Ground039_4K-JPG_Color.jpg',
|
||||
// alphaMap: '/textures/myAlphaMapTexture.jpg'
|
||||
})
|
||||
const repeat = 5
|
||||
for (const key in pbrTexture) {
|
||||
if (Object.prototype.hasOwnProperty.call(pbrTexture, key)) {
|
||||
const key_p = key as keyof typeof pbrTexture
|
||||
const element = pbrTexture[key_p]
|
||||
if (element && element.wrapS) {
|
||||
element.wrapS = RepeatWrapping
|
||||
element.wrapT = RepeatWrapping
|
||||
element.repeat.x = repeat
|
||||
element.repeat.y = repeat
|
||||
element.flipY = false
|
||||
}
|
||||
}
|
||||
}
|
||||
const { scene: top } = await useGLTF('/models_one/verh_100.glb')
|
||||
const { scene: fence } = await useGLTF('/models_one/fence.glb')
|
||||
const { scene: fastening } = await useGLTF('/models_one/krepleniye_planok (1).glb')
|
||||
const { scene: lamelle } = await useGLTF('/models_one/lamel_100.glb')
|
||||
|
||||
const { seek, seekAll } = useSeek()
|
||||
watch(section_count, () => {
|
||||
const fences = seekAll(scene.value, 'name', 'fence')
|
||||
const { seek } = useSeek()
|
||||
watch([section_count,extra_section], () => {
|
||||
const base = seek(scene.value, 'name', 'base')
|
||||
const n = (section_count.value as number)
|
||||
if (fences.length > n) {
|
||||
for (let i = fences.length; i > n; i--) {
|
||||
const item = fences[i - 1]
|
||||
if (item) {
|
||||
base?.remove(item)
|
||||
}
|
||||
}
|
||||
const n = (section_count.value as number) + ~~(!!extra_section.value)
|
||||
if (base?.children && n < base?.children.length) {
|
||||
base.children = [...base?.children.slice(0, n)]
|
||||
}
|
||||
})
|
||||
|
||||
const width = 512;
|
||||
const height = 512;
|
||||
const size = width * height;
|
||||
const data = new Uint8Array(4 * size);
|
||||
const color = new Color(0xffffff);
|
||||
const r = Math.floor(color.r * 25);
|
||||
const g = Math.floor(color.g * 25);
|
||||
const b = Math.floor(color.b * 255);
|
||||
for (let i = 0; i < size; i++) {
|
||||
const stride = i * 4;
|
||||
data[stride] = r;
|
||||
data[stride + 1] = g;
|
||||
data[stride + 2] = b;
|
||||
data[stride + 3] = 255;
|
||||
}
|
||||
const texture_one = new DataTexture(data, width, height);
|
||||
texture_one.needsUpdate = true;
|
||||
const pmremGenerator = new PMREMGenerator(renderer.value);
|
||||
pmremGenerator.compileEquirectangularShader();
|
||||
onMounted(() => {
|
||||
new EXRLoader()
|
||||
.load('/hdrmaps/kloppenheim_06_4k.exr', function (texture) {
|
||||
const exrCubeRenderTarget = pmremGenerator.fromEquirectangular(texture);
|
||||
const exrBackground = exrCubeRenderTarget.texture;
|
||||
const newEnvMap = exrCubeRenderTarget ? exrCubeRenderTarget.texture : null;
|
||||
|
||||
scene.value.environment = newEnvMap
|
||||
scene.value.background = exrBackground
|
||||
scene.value.backgroundRotation = new Euler(0, 5, 0)
|
||||
texture.dispose();
|
||||
});
|
||||
})
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = 512
|
||||
canvas.height = 512
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.fillStyle = "red"
|
||||
ctx.fillRect(10, 10, 512, 512)
|
||||
console.log(canvas.toDataURL())
|
||||
const texture = new DataTexture(ctx?.getImageData(0, 0, 512, 512).data.buffer, width, height);
|
||||
texture.needsUpdate = true;
|
||||
</script>
|
||||
<template>
|
||||
<TresGroup :translate-y="-3.25" name="base">
|
||||
<TresMesh receive-shadow :position-y="-0.5" name="ground">
|
||||
<TresCircleGeometry :args="[55, 32]" :rotate-x="-Math.PI * 0.5" />
|
||||
<TresMeshStandardMaterial :map="pbrTexture.map" :normal-map="pbrTexture.normalMap"
|
||||
:roughness-map="pbrTexture.roughnessMap" :ao-map="pbrTexture.aoMap" :metalness="0" :roughness="0.8" />
|
||||
</TresMesh>
|
||||
<TresMesh receive-shadow :position-y="-0.25" :position-x="10" name="ground">
|
||||
<TresCircleGeometry :args="[10]" :rotate-x="-Math.PI * 0.5" />
|
||||
<TresMeshStandardMaterial color="#eee" />
|
||||
</TresMesh>
|
||||
<TresMesh receive-shadow name="ground_test" :position-z="-10">
|
||||
<TresCircleGeometry :args="[5]" :rotate-x="-Math.PI * 0.5" />
|
||||
<TresMeshStandardMaterial :map="texture_one" />
|
||||
</TresMesh>
|
||||
<TresMesh receive-shadow name="ground_test" :position-z="10">
|
||||
<TresCircleGeometry :args="[5]" :rotate-x="-Math.PI * 0.5" />
|
||||
<TresMeshStandardMaterial :map="texture" />
|
||||
</TresMesh>
|
||||
<TresMesh :position="[-9, 0, 2]" cast-shadow receive-shadow>
|
||||
<TresBoxGeometry :args="[1, 1, 1]" />
|
||||
<TresMeshStandardMaterial :map="texture_one" />
|
||||
</TresMesh>
|
||||
<template v-for="i in section_count">
|
||||
<TresGroup name="base">
|
||||
<template v-for="i in (section_count + ~~(!!extra_section))">
|
||||
<template v-if="i <= 20">
|
||||
<ModelFence :index="i" :models="{ top, fence, fastening, lamelle }" />
|
||||
</template>
|
||||
|
|
Before Width: | Height: | Size: 39 MiB After Width: | Height: | Size: 48 MiB |
Before Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 2.0 MiB |
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0"?>
|
||||
<materialx version="1.38" fileprefix="./">
|
||||
<standard_surface ypos="-1.879310" name="Grass004_2K_PNG_StandardSurface" type="surfaceshader" xpos="6.159420">
|
||||
<input name="specular" type="float" value="0" />
|
||||
<input name="coat" type="float" value="1" />
|
||||
<input name="coat_color" type="color3" value="1, 1, 1" />
|
||||
<input name="base" type="float" value="1" />
|
||||
<input name="base_color" type="color3" nodename="Grass004_2K_PNG_Color" />
|
||||
<input name="normal" type="vector3" nodename="normalmap" />
|
||||
<input name="coat_normal" type="vector3" nodename="normalmap" />
|
||||
<input name="specular_roughness" type="float" nodename="Grass004_2K_PNG_Roughness" />
|
||||
<input name="coat_roughness" type="float" nodename="Grass004_2K_PNG_Roughness" />
|
||||
</standard_surface>
|
||||
<surfacematerial ypos="0.000000" name="Grass004_2K_PNG" type="material" xpos="8.695652">
|
||||
<input name="surfaceshader" type="surfaceshader" nodename="Grass004_2K_PNG_StandardSurface" />
|
||||
<input name="displacementshader" type="displacementshader" nodename="displacement" />
|
||||
</surfacematerial>
|
||||
<tiledimage ypos="-3.103448" name="Grass004_2K_PNG_Color" type="color3" xpos="3.623188">
|
||||
<input colorspace="srgb_texture" name="file" type="filename" value="Grass004_2K-PNG_Color.png" />
|
||||
<input name="uvtiling" type="vector2" value="1.0, 1.0" />
|
||||
</tiledimage>
|
||||
<tiledimage ypos="5.163793" name="Grass004_2K_PNG_Displacement" type="float" xpos="3.623188">
|
||||
<input name="file" type="filename" value="Grass004_2K-PNG_Displacement.png" />
|
||||
<input name="uvtiling" type="vector2" value="1.0, 1.0" />
|
||||
</tiledimage>
|
||||
<displacement ypos="1.879310" name="displacement" type="displacementshader" xpos="6.159420">
|
||||
<input name="displacement" type="float" nodename="Grass004_2K_PNG_Displacement" />
|
||||
<input name="scale" type="float" value="1.0" />
|
||||
</displacement>
|
||||
<tiledimage ypos="0.879310" name="Grass004_2K_PNG_NormalGL" type="vector3" xpos="1.086957">
|
||||
<input name="file" type="filename" value="Grass004_2K-PNG_NormalGL.png" />
|
||||
<input name="uvtiling" type="vector2" value="1.0, 1.0" />
|
||||
</tiledimage>
|
||||
<normalmap ypos="3.586207" name="normalmap" type="vector3" xpos="3.623188">
|
||||
<input name="in" type="vector3" nodename="Grass004_2K_PNG_NormalGL" />
|
||||
<input name="scale" type="float" value="1.0" />
|
||||
</normalmap>
|
||||
<tiledimage ypos="-0.413793" name="Grass004_2K_PNG_Roughness" type="float" xpos="3.623188">
|
||||
<input name="file" type="filename" value="Grass004_2K-PNG_Roughness.png" />
|
||||
<input name="uvtiling" type="vector2" value="1.0, 1.0" />
|
||||
</tiledimage>
|
||||
</materialx>
|
After Width: | Height: | Size: 3.3 MiB |
After Width: | Height: | Size: 8.0 MiB |
After Width: | Height: | Size: 7.5 MiB |
Before Width: | Height: | Size: 25 MiB After Width: | Height: | Size: 23 MiB |
Before Width: | Height: | Size: 27 MiB After Width: | Height: | Size: 23 MiB |
After Width: | Height: | Size: 3.1 MiB |
After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 13 MiB After Width: | Height: | Size: 13 MiB |
After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 11 MiB After Width: | Height: | Size: 11 MiB |
After Width: | Height: | Size: 5.0 MiB |
Before Width: | Height: | Size: 5.3 MiB |
Before Width: | Height: | Size: 5.9 MiB |
Before Width: | Height: | Size: 34 MiB |
Before Width: | Height: | Size: 34 MiB |
Before Width: | Height: | Size: 12 MiB |