0

Would appreciate it you can help :) even a nudge in the right direction is welcomed

Question How do I display, based on Aside component, a different Bonsai part on scroll.

Context: BonsaiPart changes the mesh based on a prop called partName. I would like to display for each Aside component a different Bonsai Part, so essentially changing the Canvas entirely.

I guess there are multiple ways to solve this and I'm curious to hear them out.

App.js

//IMPORT SCENES
import {SceneOne, SceneTwo, SceneThree } from './components/Scenes';

function App() {
  return (
      <div className="center-wrapper">
        <SceneThree />
      </div>
  );
}

export default App;

Aside Component

const Aside = (props) => {
  return (
    <div className="aside__component__content">  
      <h1>{props.title}</h1>
      <p>{props.paragraph}</p>
      <>{props.children}</>  
      <a href="#"><button className='btn btn-neutral-white-ghost'>{props.buttonText}<span>{<BsArrowDownShort size="24px" color="#9fbac8"/>}</span></button></a>
    </div>
  )
}

Bonsai Model

/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
author: padfieldelliot (https://sketchfab.com/padfieldelliot)
license: CC-BY-NC-4.0 (http://creativecommons.org/licenses/by-nc/4.0/)
source: https://sketchfab.com/3d-models/cherry-bonsai-tree-84b3db5970b64ef688024cee869be7ba
title: Cherry Bonsai Tree
*/

import React, { Suspense, useEffect, useRef } from 'react';
import { useGLTF } from '@react-three/drei';

import {useFrame} from '@react-three/fiber';

let partReturned;

function BonsaiPart( props ) {
  const partName = props.partName;
  const ref = useRef();
  const { nodes, materials } = useGLTF('bonsai_tree/scene.gltf');

  if (partName == 'tree') {
    partReturned = <mesh geometry={nodes.Object_4.geometry} material={materials.pasted__lambert3SG}>{props.children}</mesh>
  } else if (partName == "leafs") {
    partReturned = <mesh geometry={nodes.Object_5.geometry} material={materials.pasted__lambert7SG}>{props.children}</mesh>
  } else if (partName == "frame") {
    partReturned = <mesh geometry={nodes.Object_2.geometry} material={materials.lambert2SG}>{props.children}</mesh>
  } else if (partName == "dirt") {
    partReturned = <mesh geometry={nodes.Object_3.geometry} material={materials.lambert3SG}>{props.children}</mesh>
  }

  useFrame((state) => {
    const t = state.clock.getElapsedTime()
    ref.current.rotation.x = -Math.PI / 1.75 + Math.cos(t / 4) / 8
    ref.current.rotation.y = Math.sin(t / 4) / 8
    ref.current.rotation.z = (1 + Math.sin(t / 1.5)) / 20
    ref.current.position.y = (1 + Math.sin(t / 1.5)) / 10
  })

  return (
    <Suspense fallback={null}>
      <group ref={ref} {...props} dispose={null}>
        <group rotation={[-Math.PI / 2, 0, 0]}>
          {partReturned}
        </group>
      </group>
    </Suspense>
  )
}

function Bonsai( props ) {
  const { nodes, materials } = useGLTF('bonsai_tree/scene.gltf');
  /* 
  OBJECT 2 = Frame
  OBJECT 3 = Dirt
  OBJECT 4 = Tree
  OBJECT 5 = Leafs
  */
  return (
    <Suspense fallback={null}>
      <group {...props} dispose={null}>
        <group rotation={[-Math.PI / 2, 0, 0]}>
          <mesh geometry={nodes.Object_2.geometry} material={materials.lambert2SG} />
          <mesh geometry={nodes.Object_3.geometry} material={materials.lambert3SG} />
          <mesh geometry={nodes.Object_4.geometry} material={materials.pasted__lambert3SG} >
            {props.children}
          </mesh>
          <mesh geometry={nodes.Object_5.geometry} material={materials.pasted__lambert7SG} />
        </group>
      </group>
    </Suspense>
  )
}

export { Bonsai, BonsaiPart };
useGLTF.preload('bonsai_tree/scene.gltf')

Scenes.js

const SceneThree = () => {
  const { ref, inView, entry } = useInView({
    /* Optional options */
    threshold: 0,
  });
    return (
      <div className='aside__component'>
        <div className='aside__component__scroll'>
          <Canvas>
            <ScrollControls distance={.08} pages={4}>
              <Scroll html>

                <Aside
                  asideClass={"aside__component__content"}
                  title={"How Bonzen Improves Your Mental Health"}
                  buttonText={"Scroll for more"}
                  paragraph= {"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."} >
                    <ul>
                      <li><span>Price:</span> elit esse adipisicing officia quis esse.</li>
                      <li><span>Color:</span> nulla exercitation incididunt sunt mollit cillum voluptate.</li>
                      <li><span>Model:</span> officia exercitation pariatur ad amet.</li>
                      <li><span>Frame Included:</span> adipisicing exercitation velit amet eu.</li>
                    </ul>
                </Aside>

                <Aside 
                  asideClass={"aside__component__content"}
                  title={"How Bonzen Improves Your Mental Health"}
                  buttonText={"Scroll for more"}
                  paragraph={"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."}>      
                </Aside>

                <Aside
                  asideClass={"aside__component__content"}
                  title={"How Bonzen Improves Your Mental Health"}
                  buttonText={"Scroll for more"}
                  paragraph= {"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."} >
                    <p>dolore commodo mollit et pariatur veniam Lorem exercitation officia Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo</p>
                </Aside>

                <Aside
                  asideClass={"aside__component__content"}
                  title={"How Bonzen Improves Your Mental Health"}
                  buttonText={"Scroll for more"}
                  paragraph= {"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."}> 
                    <ul>
                      <li><span>Price:</span> elit esse adipisicing officia quis esse.</li>
                      <li><span>Color:</span> nulla exercitation incididunt sunt mollit cillum voluptate.</li>
                      <li><span>Model:</span> officia exercitation pariatur ad amet.</li>
                      <li><span>Frame Included:</span> adipisicing exercitation velit amet eu.</li>
                    </ul>
                </Aside>

              </Scroll>
            </ScrollControls>
          </Canvas> 
        </div>
  
        <div className='aside__webgl'>
          <Canvas camera={{fov: 40, near: 5, far: 20 }} linear>
            <Stage contactShadow shadows intensity={.5} environment="sunset" preset='rembrandt'>
              <PresentationControls config={{ mass: 2, tension: 50 }} polar={[0, 0.02]} >
                <Bonsai scale={[1.2,1.2,1.2]}></Bonsai>
              </PresentationControls>
            </Stage>
          </Canvas>
        </div>
      </div>
    )
  }

export { SceneOne, SceneTwo, SceneThree };

Desire:

1 Answers1

0

I've done it but I think it is not an appropriate way to solve it.

the main change was to add to each Aside component a div wrapper with it's useInView reference and switch the model imported based on the component in view.

const SceneThree = (props) => {

  const [bonsaiRef, bonsaiView] = useInView();
  const [treeRef, treeView] = useInView();
  const [leafsRef, leafsView] = useInView();
  const [dirtRef, dirtView] = useInView();

  if (bonsaiView) {
    partReturned = <><Bonsai scale={[1.2,1.2,1.2]}/></>
  } else if (treeView) {
    partReturned = <><BonsaiPart partName={"tree"} scale={[1,1,1]}/></>
  } else if (leafsView) {
    partReturned = partReturned = <><BonsaiPart partName={"leafs"} scale={[1,1,1]}/></>
  } else if (dirtView) {
    partReturned = partReturned = <><BonsaiPart partName={"dirt"} scale={[1,1,1]}/></>
  }

  return (
      <div className='aside__component'>
        <div {...props} className='aside__component__scroll'>
          <Canvas>
            <ScrollControls distance={.08} pages={4}>
              <Scroll html>
                
                <div ref={bonsaiRef}>
                  <Aside
                    title={"Spark Your Life"}
                    buttonText={"Read more"}
                    paragraph= {"Marco was a not this model. He was lazy, scared of the uknown who thought only great stuff about himself ( p.s: he was not! ). After he received as a gift his Bonzen, Marco couldn't be recognized anymore! Find out how down below."}>
                      <ul>
                        <li><span>Price: </span> smallest size starts at 24.99$</li>
                        <li><span>Color: </span> 3 frame color variants</li>
                        <li><span>Custom: </span>Customize your Bonzen Frame</li>
                      </ul>
                  </Aside>
                </div>

                <div ref={treeRef}>
                  <Aside
                    // ref={ref}
                    title={"Nurture Self-Confidence"}
                    buttonText={"Scroll for more"}
                    paragraph={"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."}>      
                  </Aside>
                </div>

                <div ref={leafsRef}>
                  <Aside
                    title={"Greater Self-Awareness"}
                    buttonText={"Scroll for more"}
                    paragraph= {"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."} >
                      <p>dolore commodo mollit et pariatur veniam Lorem exercitation officia Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo</p>
                  </Aside>
                </div>

                <div ref={dirtRef}>
                  <Aside
                    title={"Work With Compassion"}
                    buttonText={"Scroll for more"}
                    paragraph= {"Labore fugiat et ut dolore commodo mollit et pariatur veniam Lorem exercitation officia. Elit nulla nulla commodo eiusmod et veniam occaecat ipsum dolore eu incididunt eiusmod."}> 
                      <ul>
                        <li><span>bacteria free:</span> no dangerous bacterias included</li>
                        <li><span>Pleasing:</span> stay focused with your buddy </li>
                        <li><span>Air purifier:</span> breath clean and fresh new air</li>
                      </ul>
                  </Aside>
                </div>

              </Scroll>
            </ScrollControls>
          </Canvas> 
        </div>
  
        <div className='aside__webgl'>
          <Canvas camera={{fov: 40, near: 5, far: 20 }} linear>
            <Stage contactShadow shadows intensity={.5} environment="sunset" preset='rembrandt'>
              <PresentationControls config={{ mass: 2, tension: 50 }} polar={[0, 0.02]} >
                {partReturned}
              </PresentationControls>
            </Stage>
          </Canvas>
        </div>
      </div>
    )
  }