Untitled

 avatar
unknown
plain_text
a month ago
8.3 kB
2
Indexable
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import {
  Scene,
  PerspectiveCamera,
  PCFSoftShadowMap,
  AnimationMixer,
  Clock,
  MeshBasicMaterial,
  DoubleSide, // Remove the second instance here
  TextureLoader, // Remove the second instance here
  LinearMipMapLinearFilter,
  ReinhardToneMapping,
  LoopOnce,
  Fog,
  FogExp2,
} from 'three';
import { setupRenderer } from '../helpers/RendererHelper.js';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

const loader = new GLTFLoader();
const clock = new Clock();

let scene, camera, renderer, mixer, action;
let duration = 0;

// Load the alpha texture
const textureLoader = new TextureLoader();

// Load the PNG image for HDRI (using as an environment map)
const hdriTexturePath = './src/assets/hdri.png'; // Replace with the path to your PNG image
const hdriTexture = textureLoader.load(hdriTexturePath);

const monsteraAlphaTexturePath = './src/models/Monstera Plant_AlphaMain.png'; // Replace with the path to your alpha texture
const monsteraAlphaTexture = textureLoader.load(monsteraAlphaTexturePath);

const otherPlantAlphaTexturePath = './src/models/OtherPlant_Alpha.png'; // Replace with the path to your alpha texture
const otherPlantAlphaTexture = textureLoader.load(otherPlantAlphaTexturePath);

const scrunchieAlphaTexturePath = './src/models/Scrunchie Box Alpha.png'; // Replace with the path to your alpha texture
const scrunchieAlphaTexture = textureLoader.load(scrunchieAlphaTexturePath);

export function setupScene(canvas) {
  // Accept canvas as a parameter
  scene = new Scene();

  // ADD FOG
  const fogColor = 0x505050;
  const fogNear = 5;
  const fogFar = 200;

  scene.fog = new Fog(fogColor, fogNear, fogFar);

  console.log(scene.fog);

  // Set up a fallback camera (in case no GLTF camera exists)
  camera = new PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    500,
  );

  camera.near = 0.1;
  camera.far = 500;
  camera.updateProjectionMatrix();

  // Set up renderer
  renderer = setupRenderer(canvas);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.toneMapping = ReinhardToneMapping;
  renderer.toneMappingExposure = 6.0;
  // renderer.useLegacyLights = true;
  renderer.shadowMap.enabled = true;

  renderer.shadowMap.type = PCFSoftShadowMap;
  renderer.sortObjects = true;

  // Apply the PNG as environment map
  scene.background = hdriTexture;
  scene.environment = hdriTexture;

  // Load the GLTF model
  loadModel();
}

function loadModel() {
  loader.load('./src/models/VRworld.glb', (gltf) => {
    const model = gltf.scene;

    model.traverse((child) => {
      if (child.isMesh) {
        const bakedMaterial = new MeshBasicMaterial({
          map: child.material.map, // Apply the baked texture
          color: 0xffffff, // Keep white to avoid altering the texture colors
          side: DoubleSide, // Turn off backface culling
          fog: true,
        });
        child.material = bakedMaterial;
        child.castShadow = true;
        child.receiveShadow = true;
        child.material.transparent = true;
        child.material.side = DoubleSide;
        child.material.depthWrite = true;
        child.material.depthTest = true;
        child.material.specular = null;

        // Ensure mipmaps are generated for textures
        if (child.material.map) {
          child.material.map.generateMipmaps = true;
          child.material.map.minFilter = LinearMipMapLinearFilter;
        }

        if (['Monstera_Plant001', 'Monstera_Plant'].includes(child.name)) {
          child.material.transparent = true;
          child.material.alphaMap = monsteraAlphaTexture;

          // Flip the alpha texture 180 degrees
          monsteraAlphaTexture.repeat.set(1, -1); // Flip horizontally and vertically
          monsteraAlphaTexture.offset.set(0, 1); // Adjust the offset so the flip appears correctly

          child.material.alphaMap.needsUpdate = true;
        }

        if (['Other_Plant'].includes(child.name)) {
          child.material.transparent = true;
          child.material.alphaMap = otherPlantAlphaTexture;
          otherPlantAlphaTexture.repeat.set(1, -1); // Flip horizontally and vertically
          otherPlantAlphaTexture.offset.set(0, 1); // Adjust the offset so the flip appears correctly
          child.material.alphaMap.needsUpdate = true;
        }

        if (
          [
            'PillowCase_Box',
            'PillowCaseCover',
            'PillowSilkCover',
            'Text001',
          ].includes(child.name)
        ) {
          if (child.material) {
            child.material.emissiveIntensity = 0.1;
          }
        }

        if (
          [
            'Scrunchie_Box',
            'Scrunchie_Box001',
            'Scrunchie_Box002',
            'Scrunchie_Box004',
            'Scrunchie_Box003',
          ].includes(child.name)
        ) {
          child.material.transparent = true;
          child.material.alphaMap = scrunchieAlphaTexture;

          // Flip the alpha texture 180 degrees
          scrunchieAlphaTexture.repeat.set(1, -1); // Flip horizontally and vertically
          scrunchieAlphaTexture.offset.set(0, 1); // Adjust the offset so the flip appears correctly

          child.material.alphaMap.needsUpdate = true;
        }
      }
    });

    scene.add(model);

    if (gltf.cameras && gltf.cameras.length > 0) {
      camera = gltf.cameras[0];
    }

    mixer = new AnimationMixer(model);
    const animations = gltf.animations;

    if (animations.length > 0) {
      animations.forEach((animation) => {
        const action = mixer.clipAction(animation);
        action.play(); // Play each animation
        action.loop = LoopOnce;
        action.clampWhenFinished = true;
      });
      duration = animations[0].duration;
      enableScrollWheelControl();
    }

    animate();
  });
}

function enableScrollWheelControl() {
  let scrollSpeed = 0.005; // Adjust this for sensitivity
  let currentAnimationTime = 0;

  window.addEventListener('wheel', (event) => {
    if (!mixer || !duration) return;

    // Update animation time based on scroll direction and speed
    currentAnimationTime += event.deltaY * scrollSpeed;
    currentAnimationTime = Math.max(
      0,
      Math.min(duration, currentAnimationTime),
    ); // Clamp to animation duration

    // Manually update the animation mixer to reflect the scroll-based time
    mixer.setTime(currentAnimationTime);
  });
}

function updateCameraFromAnimation(animationTime) {
  if (!mixer || !mixer._actions.length) return; // Ensure there are actions in the mixer

  const animationAction = mixer._actions[0]; // Get the first action
  if (!animationAction || !animationAction.getClip()) return; // Ensure there is a valid action

  const animationClip = animationAction.getClip(); // Get the clip
  if (!animationClip) return;

  // Check for camera-related tracks in the animation
  const cameraTracks = animationClip.tracks.filter((track) =>
    track.name.startsWith('Camera'),
  );

  if (cameraTracks.length === 0) {
    console.warn('No camera tracks found in the animation');
    return;
  }

  cameraTracks.forEach((track) => {
    // Handle position updates
    if (track.name.endsWith('.position')) {
      const position = track.interpolate(animationTime);
      camera.position.set(position[0], position[1], position[2]);
    }

    camera.near = 0.1;
    camera.updateProjectionMatrix();

    // Handle rotation updates (quaternion)
    if (track.name.endsWith('.quaternion')) {
      const quaternion = track.getValueAt(animationTime);
      camera.quaternion.set(
        quaternion[0],
        quaternion[1],
        quaternion[2],
        quaternion[3],
      );
    }
  });
}

function animate() {
  requestAnimationFrame(animate);
  const delta = clock.getDelta();

  if (mixer) {
    mixer.update(delta);
  }

  renderer.render(scene, camera);
}
Leave a Comment