admin管理员组

文章数量:1410724

I’m building a next.js app (v.15 with app router) and I’m having some issues with my glb file/model after building/deploying my app. I have a CI that deploys my app to GCP using docker(artifact registry) cloud run. But I don’t think the issue is with the deploy. If I check my builded/deployed app in devtools>network I can see my glb file there, also if I type myExampleUrl/myglbfile.glb in the browser my file starts to download. So the file is there.

I have added this to my next.config.ts

transpilePackages: ['three', '@react-three/fiber', '@react-three/drei'], 

The model is in my frontpage hero component. I have devided it in 2 components: scene and model.

Here is my ThreeScene/ThreeScenetsx

import {useEffect} from 'react'; import {Canvas} from '@react-three/fiber' import Model from './Model' import {Environment} from "@react-three/drei"; export default function ThreeScene() { useEffect(() => { if (!window.WebGLRenderingContext) { console.error("WebGL not supported"); } else { console.log("WebGL supported"); } }, []); return ( <Canvas> <directionalLight intensity={.1} position={[0, 3, 2]}/> <Environment preset="city"/> <Model/> </Canvas> ) } 

And here is my ThreeScene/Model.tsx

import {useGLTF} from "@react-three/drei";
import {useFrame, useThree} from "@react-three/fiber";
import React, {useRef, useState, useEffect} from "react";
import {Group, Vector2} from "three";
import gsap from "gsap";
import {useGSAP} from "@gsap/react";

export default function Model() {
    const groupRef = useRef<Group>(null);
    const [pointer] = useState(new Vector2());
    const {nodes, materials} = useGLTF("/heroobject.glb");
    const {viewport, size} = useThree(); // Här läggs size till i destructuring
    const [isAnimating, setIsAnimating] = useState(true);
    const [isInitialized, setIsInitialized] = useState(false);

    const getScaleFactor = (width: number) => {
        if (width <= 768) {
            return 1.2; // mobile
        } else if (width <= 1024) {
            return 2.3; // tablet
        } else {
            return 3.2; //desktop
        }
    };

    useGSAP(() => {
        if (groupRef.current && !isInitialized) {
            setIsInitialized(true);

            groupRef.current.scale.set(0, 0, 0);
            groupRef.current.rotation.set(0, 0, 0);
            groupRef.current.position.y = 0;

            const scaleFactor = getScaleFactor(size.width);

            gsap.to(groupRef.current.scale, {
                x: viewport.width / scaleFactor,
                y: viewport.width / scaleFactor,
                z: viewport.width / scaleFactor,
                delay: .5,
                duration: 1.5,
                ease: "elastic.out(1, 0.5)",
                "onComplete": () => setIsAnimating(false)
            });

            gsap.to(groupRef.current.position, {
                y: 0.75,
                duration: 1.5,
                ease: "power3.out"
            });

            gsap.to(groupRef.current.rotation, {
                y: Math.PI * 2,
                duration: 2,
                ease: "power2.inOut"
            });
        }
    }, [isInitialized, size.width, viewport.width]);

    useEffect(() => {
        if (groupRef.current && isInitialized && !isAnimating) {
            const scaleFactor = getScaleFactor(size.width);

            gsap.to(groupRef.current.scale, {
                x: viewport.width / scaleFactor,
                y: viewport.width / scaleFactor,
                z: viewport.width / scaleFactor,
                duration: 0.5,
                ease: "power2.out"
            });
        }
    }, [size.width, viewport.width, isInitialized, isAnimating]);

    useFrame((state) => {
        pointer.set(state.pointer.x, state.pointer.y);

        if (groupRef.current && !isAnimating) {
            groupRef.current.rotation.y += 0.004;

            const targetRotationX = pointer.y * 0.2;
            const targetRotationZ = pointer.x * 0.2;

            groupRef.current.rotation.x += (targetRotationX - groupRef.current.rotation.x) * 0.05;
            groupRef.current.rotation.z += (targetRotationZ - groupRef.current.rotation.z) * 0.05;
        }
    });

    const cylinderNames = [
        "Cylinder", "Cylinder001", "Cylinder002", "Cylinder003",
        "Cylinder004", "Cylinder005", "Cylinder006"
    ];

    return (
        <group ref={groupRef} position={[0, 0, 0]}>
            {cylinderNames.map((name: string) => (
                <primitive
                    key={name}
                    object={nodes[name]}
                    material={materials["Material.001"]}
                />
            ))}
        </group>
    );

I’m then importing ThreeScene in my hero component.

Any ideas? If anyone wants to take a closer look I would love to invite you to my gitlab repo.

I have tried to use next/dynamic and imported ThreeScene with ssr:false, I have tried several different config settings. The file is there I just can’t see the model.

本文标签: typescriptThreejsR3F with nextjs builddeploy issueStack Overflow