Hi. I am new to threejs and I am not sure if I can explain it good. But my idea is that I have a 3D laptop model and instead of one object (laptop screen) I am using a portal that is showing another component (which has a tunnel effect). I am using gsap to rotate the laptop model and then it zooms in to the screen. This works so far ok. But I couldnt find the way to zoom into the portal component. Currently I have this:
import React, { useRef, useEffect, useState, useMemo } from "react";
import { useGLTF, useDetectGPU } from "@react-three/drei";
import { useFrame, useThree, createPortal } from "@react-three/fiber";
import * as THREE from "three";
import PotatoEffect from "./wormhole/PotatoEffect";
const Model = ({ url, roughness, metalness, scrollProgress }) => {
const { scene } = useGLTF(url);
const modelRef = useRef();
const lidRef = useRef();
const screenRef = useRef();
const isInitialRender = useRef(true);
const [textureLoaded, setTextureLoaded] = useState(false);
const gpuTier = useDetectGPU();
const { gl } = useThree();
const [wormholeTarget] = useState(
() => new THREE.WebGLRenderTarget(512, 512)
);
const wormholeScene = useMemo(() => new THREE.Scene(), []);
const wormholeCamera = useMemo(
() => new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10),
[]
);
useEffect(() => {
wormholeCamera.position.z = 1;
}, [wormholeCamera]);
useEffect(() => {
if (modelRef.current) {
modelRef.current.position.set(0, -3, 0);
modelRef.current.rotation.y = -Math.PI / 2;
const lidObject = scene.getObjectByName("Cube016_2");
if (lidObject) {
lidRef.current = lidObject;
lidRef.current.rotation.x = 0;
console.log("Lid object found:", lidObject);
const screenObject = lidObject.getObjectByName("Object_21");
if (screenObject) {
screenRef.current = screenObject;
console.log("Screen object found:", screenObject);
const newMaterial = new THREE.MeshBasicMaterial({
map: wormholeTarget.texture,
side: THREE.DoubleSide,
});
screenRef.current.material = newMaterial;
setTextureLoaded(true);
} else {
console.log("Screen object (Object_21) not found");
}
} else {
console.log("Lid object (Cube016_2) not found");
}
}
}, [scene, wormholeTarget.texture]);
useFrame((state) => {
if (modelRef.current && lidRef.current) {
const targetRotationY = THREE.MathUtils.lerp(
-Math.PI / 2,
0,
scrollProgress
);
const maxLidRotation = Math.PI / 2;
const targetLidRotation = -scrollProgress * maxLidRotation;
const startZ = 0;
const endZ = 2;
const targetZ = THREE.MathUtils.lerp(startZ, endZ, scrollProgress);
// Floating animation
const floatOffset = Math.sin(state.clock.elapsedTime) * 0.1;
const targetY = -3 + floatOffset;
if (isInitialRender.current) {
modelRef.current.rotation.y = targetRotationY;
lidRef.current.rotation.x = targetLidRotation;
modelRef.current.position.z = targetZ;
modelRef.current.position.y = targetY;
isInitialRender.current = false;
} else {
modelRef.current.rotation.y +=
(targetRotationY - modelRef.current.rotation.y) * 0.1;
lidRef.current.rotation.x +=
(targetLidRotation - lidRef.current.rotation.x) * 0.1;
modelRef.current.position.z +=
(targetZ - modelRef.current.position.z) * 0.1;
modelRef.current.position.y +=
(targetY - modelRef.current.position.y) * 0.1;
}
}
scene.traverse((child) => {
if (child.isMesh && child.material && child !== screenRef.current) {
child.material.roughness = roughness;
child.material.metalness = metalness;
}
});
// Render wormhole effect to texture
gl.setRenderTarget(wormholeTarget);
gl.render(wormholeScene, wormholeCamera);
gl.setRenderTarget(null);
});
return (
<>
<primitive ref={modelRef} object={scene} />
{createPortal(<PotatoEffect />, wormholeScene)}
</>
);
};
export default Model;
Basically it would go fullscreen into the portal. Not sure if this is posssible with threejs? I tried a lot of stuff but can’t get further. Any advice? I just need the starting point.