add interactive 3D sample animated by threejs
This commit is contained in:
parent
ee4e6adf06
commit
32dc56f9dd
17 changed files with 165 additions and 26 deletions
71
src/components/VirtualSample.vue
Normal file
71
src/components/VirtualSample.vue
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div class="virtual-sample" ref="virtualSampleContainer"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import * as THREE from "three";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
|
||||
const virtualSampleContainer = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
const container = virtualSampleContainer.value;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
75,
|
||||
container.clientWidth / container.clientHeight,
|
||||
0.1,
|
||||
1000
|
||||
);
|
||||
const renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
renderer.setClearColor(0xffffff, 1);
|
||||
container.appendChild(renderer.domElement);
|
||||
|
||||
const light = new THREE.AmbientLight(0xffffff);
|
||||
scene.add(light);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.load(
|
||||
"/assets/3D/flacon-test.glb",
|
||||
(gltf) => {
|
||||
const model = gltf.scene;
|
||||
scene.add(model);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
console.error("Erreur lors du chargement du modèle", error);
|
||||
}
|
||||
);
|
||||
|
||||
camera.position.set(3, 2, 5);
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.05;
|
||||
|
||||
const animate = () => {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
camera.aspect = container.clientWidth / container.clientHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.virtual-sample {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -3,17 +3,15 @@
|
|||
<div
|
||||
id="inspirations-dropdown"
|
||||
class="flex flex-col"
|
||||
style="
|
||||
--image: url('https://plus.unsplash.com/premium_photo-1675626791716-7f74187592f1?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D');
|
||||
"
|
||||
:style="'--image: url(\'' + current.cover + '\');'"
|
||||
>
|
||||
<label for="inspirations-select" class="text-sm">Choisir une inspiration</label>
|
||||
<label for="inspirations-select" class="text-sm"
|
||||
>Choisir une inspiration</label
|
||||
>
|
||||
<Select
|
||||
id="inspirations-select"
|
||||
v-model="selectedInspiration"
|
||||
:options="inspirations"
|
||||
optionLabel="name"
|
||||
optionValue="value"
|
||||
v-model="current.uri"
|
||||
:options="all"
|
||||
class="font-serif"
|
||||
data-icon="chevron-single-down"
|
||||
checkmark
|
||||
|
|
@ -22,13 +20,23 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
const selectedInspiration = ref("shape-of-nature");
|
||||
const inspirations = ref([
|
||||
{ name: "Shape of Nature", value: "shape-of-nature" },
|
||||
{ name: "Inspiration Title", value: "inspiration-title" },
|
||||
]);
|
||||
const { all } = defineProps({
|
||||
all: Array,
|
||||
});
|
||||
|
||||
const current = ref(all[0]);
|
||||
|
||||
watch(current, (newValue) => {
|
||||
console.log(newValue);
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:currentInspiration"]);
|
||||
|
||||
function changeInspiration(inspirationUri) {
|
||||
emit("update:currentInspiration", inspirationUri);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
@ -80,7 +88,6 @@ const inspirations = ref([
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
/* Icon */
|
||||
#inspirations-select svg {
|
||||
display: none; /* Hide default component svg */
|
||||
|
|
@ -89,10 +96,10 @@ const inspirations = ref([
|
|||
--icon-color: var(--color-grey-700);
|
||||
position: absolute;
|
||||
right: var(--space-8);
|
||||
top: .625rem;
|
||||
top: 0.625rem;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
padding: .625rem;
|
||||
padding: 0.625rem;
|
||||
}
|
||||
#inspirations-dropdown label {
|
||||
color: var(--color-grey-700);
|
||||
|
|
@ -144,7 +151,7 @@ const inspirations = ref([
|
|||
/* Check */
|
||||
#inspirations-select_list > * > svg {
|
||||
position: absolute;
|
||||
left: .875rem;
|
||||
left: 0.875rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
color: var(--color-grey-700);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue