new model

This commit is contained in:
T-A-H-prog
2026-09-10 18:25:28 +02:00
parent 109985a921
commit 6eaa10e34f
8 changed files with 266 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1,263 @@
<script setup lang="js">
import { onMounted, onUnmounted, ref } from "vue";
import * as THREE from "three";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import ski_video from "/vids/th.mp4";
import normal_texture from "../../assets/myself/terminalretro.jpg";
const canvasRef = ref(null);
let renderer, scene, camera, model, controls, gsapCtx;
let raycaster;
let mouse;
let screens;
const video_ski = document.createElement("video");
video_ski.src = ski_video;
video_ski.loop = true;
video_ski.muted = true;
function initThree(canvas) {
renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true,
});
renderer.setPixelRatio(1); //TODO
renderer.outputColorSpace = THREE.SRGBColorSpace;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(23, 1, 0.1, 140);
// const light = new THREE.DirectionalLight(0xffe0b0, 0.9);
// light.position.set(-1, 4, 5);
// scene.add(light);
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// controls.enabled = false;
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
// controls.minDistance = 5;
// controls.maxDistance = 5;
controls.maxPolarAngle = Math.PI / 2;
controls.minAzimuthAngle = -Math.PI / 2;
controls.maxAzimuthAngle = Math.PI / 2;
scene.add(new THREE.AmbientLight(0xffffff, 0.02));
loadModel();
gsap.ticker.add(render);
}
function loadModel() {
const modelUrl = "/models/book_shelf_pc_draco-v1.glb";
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("/draco/");
const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
loader.load(
modelUrl,
(gltf) => {
model = gltf.scene;
scene.add(model);
// Bounding Box nach dem Hinzufügen bestimmen
const box = new THREE.Box3().setFromObject(model);
const center = box.getCenter(new THREE.Vector3());
const size = box.getSize(new THREE.Vector3());
const maxSize = Math.max(size.x, size.y, size.z);
// Kamera passend zum Objekt positionieren
const distance = maxSize * 2;
screen = model.getObjectByName("fernseher1Bild");
// camera.position.set(center.x, center.y, center.z + distance);
// camera.lookAt(center);
camera.position.set(
center.x,
center.y + distance * 0.35, // etwas von oben
center.z + distance,
);
camera.lookAt(center);
controls.target.copy(center);
controls.update();
// OrbitControls auf das Objekt ausrichten
controls.target.copy(center);
controls.update();
console.log("Model geladen:", model);
console.log("Center:", center);
console.log("Size:", size);
const bulb = model.getObjectByName("light");
if (bulb) {
console.log("Glühbirne gefunden:", bulb);
const pointLight = new THREE.PointLight(
0xffd6a3, // Farbe
5, // Intensität
10, // Reichweite
);
bulb.add(pointLight);
}
document.title = "Model geladen";
},
(progress) => {
if (progress.total) {
const percent = ((progress.loaded / progress.total) * 100).toFixed(1);
console.log(`Loading: ${percent}%`);
}
},
(error) => {
console.error("Fehler beim Laden des Modells:", error);
document.title = "Fehler beim Laden!";
},
);
}
const screen_on = ref(false);
function onCanvasClick(event) {
const rect = canvasRef.value.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const screen = model?.getObjectByName("screen");
if (!screen) return;
const intersects = raycaster.intersectObject(screen, true);
const texure_ski = new THREE.VideoTexture(video_ski);
texure_ski.flipY = false;
// texure_ski.offset.set(0.3, 2);
// texure_ski.center.set(0.5, 0.5);
texure_ski.repeat.set(4.3, 4.3);
texure_ski.offset.set(-0.3, -0.33);
const normalTexture = new THREE.TextureLoader().load(normal_texture);
normalTexture.flipY = false;
normalTexture.repeat.set(5.6, 5.6);
normalTexture.offset.set(-0.54, -0.5);
if (intersects.length > 0) {
if (screen_on.value) {
screen.material = new THREE.MeshBasicMaterial({
map: normalTexture,
});
video_ski.pause();
} else {
screen.material = new THREE.MeshBasicMaterial({
map: texure_ski,
});
video_ski.play();
}
screen_on.value = !screen_on.value;
}
}
function render() {
if (!renderer) return;
controls.update();
renderer.render(scene, camera);
}
function onResize() {
if (!renderer || !canvasRef.value) return;
const r = canvasRef.value.getBoundingClientRect();
const dpr = Math.min(window.devicePixelRatio || 1, 2);
const width = canvasRef.value.clientWidth;
const height = canvasRef.value.clientHeight;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(width, height, false);
camera.aspect = (r.width || 1) / (r.height || 1);
camera.updateProjectionMatrix();
}
const resizeObserver = new ResizeObserver(onResize);
onMounted(() => {
initThree(canvasRef.value);
onResize();
canvasRef.value.addEventListener("click", onCanvasClick);
resizeObserver.observe(canvasRef.value);
window.addEventListener("resize", onResize);
});
onUnmounted(() => {
gsap.ticker.remove(render);
window.removeEventListener("resize", onResize);
canvasRef.value?.removeEventListener("click", onCanvasClick);
resizeObserver.disconnect();
renderer?.dispose();
gsapCtx?.revert();
// ScrollTrigger.getAll().forEach((t) => t.kill());
});
</script>
<template>
<div class="wrapper">
<!-- <div class="spacer"></div> -->
<canvas class="canvas" ref="canvasRef"></canvas>
</div>
<div class="scroll-buffer"></div>
<div class="spacer"></div>
</template>
<style>
.spacer {
width: 100%;
height: 200vh;
display: grid;
place-items: center;
font-weight: 600;
}
.wrapper {
width: 100%;
height: 100vh;
}
.canvas {
width: 100%;
height: 100%;
}
.scroll-buffer {
height: 100vh;
}
</style>

View File

@@ -9,6 +9,7 @@ import ScrollTrigger from "gsap/ScrollTrigger";
import ScrollSmoother from "gsap/ScrollSmoother";
import MonitorModel from "../components/big/MonitorModel.vue";
import IntroductionSection from "../components/big/IntroductionSection.vue";
import PcBooks from "../components/big/PcBooks.vue";
// import NewTextSection from "../components/sections/NewTextSection.vue";
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
@@ -42,6 +43,7 @@ onUnmounted(() => {
<IntroductionSection />
<MonitorModel id="model" />
<PcBooks id="model_pc" />
<!-- <HeroSection id="hero" /> -->
<!-- <ImageSection id="image" /> -->
<TextSection id="text" />

View File

@@ -146,7 +146,7 @@ onUnmounted(() => {
<style scoped>
.component-wrapper {
position: relative
position: relative;
width: 100%;
}