Adding Trackball Controls to a Three.js Scene with Sprites answer re: How to change the zOrder of object with Threejs?

저는 마인드맵을 기반으로 소셜 미디어 네트워크 및 협업 도구를 구축하고 있으며 이 블로그 게시물 시리즈에서 제 작업을 문서화하고 있습니다. React, Tailwind CSS, Firebase, Apollo/GraphQL, three.js 및 TypeScript를 사용하여 웹 앱을 구축하는 과정에서 제가 배운 내용에 관심이 있으시면 저를 팔로우하세요.

오늘의 목표



이 시리즈의 이전 파트에서는 ​​three.js을 사용하여 Reactforce-directed graph으로 마인드 맵을 구축했습니다.

일부 댓글 작성자는 (당연히) 마인드 맵을 그리기 위해 완전한 3D 렌더링 라이브러리를 사용해야 하는 이유를 물었습니다. 2D 캔버스에 그리거나 SVG 또는 DOM 노드를 사용하여 텍스처링, 카메라 각도 계산, 스프라이트 렌더링 등의 후프를 건너뛰지 않고도 동일합니다.

글쎄요, 프로젝트에 대한 제 비전은 유동적이고 애니메이션화된 사용자 경험을 제공하는 것입니다. 마음 속의 생각이 멈추지 않는 것처럼 제 마인드 맵은 항상 움직여야 합니다.

오늘 저는 마인드 맵을 확대/축소, 회전 및 이동하는 기능을 추가하여 그 방향으로 중요한 단계를 밟고 실제로 3D 모델만이 제공할 수 있는 수준의 상호 작용을 달성하고자 합니다.

Three.js 트랙볼 컨트롤



three.js에 있는 대부분의 예제는 "Trackball Controls"라는 라이브러리를 사용하여 데모에 확대/축소, 회전 및 패닝을 추가합니다. 그것은 실제로 라이브러리가 아니며 누군가가 작성한 평범한 오래된 JavaScript 프로그램으로 모든 곳에서 복사됩니다. "공식 파일"은 three.js 소스 코드found in the examples directory입니다.

이것은 모듈 가져오기를 지원하지 않고 전역 변수를 사용하는 "오래된"JavaScript이지만 운 좋게도 누군가 npm 패키지로 포장하고 사용 방법에 대한 유용한 정보를 추가했습니다.
  • three-trackballcontrols

  • 이 라이브러리를 내 마인드 맵 데모에 추가하고 내 initializeScene 함수에 코드를 추가하여 "연결"합니다.

    function initializeScene(div) {
      const canvas = createCanvas(window.innerWidth, window.innerHeight);
      const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
      div.appendChild(renderer.domElement);
    
      const scene = new THREE.Scene();
      scene.background = new THREE.Color(0xffffff);
    
      const camera = new THREE.PerspectiveCamera(
        50,
        window.innerWidth / window.innerHeight,
        0.1,
        500000
      );
      camera.position.z = 1.5;
    
      const controls = new TrackballControls(camera, renderer.domElement);
    
      return { scene, renderer, camera, controls };
    }
    
    scene , renderercamera 외에도 이 함수는 이제 controls 개체도 내보냅니다.

    renderMindMap 함수에서 이것을 사용하여 다음과 같이 내 animate 루프 내부의 카메라 위치를 업데이트합니다.

    (function animate() {
      graph.tickFrame();
      controls.update();
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
    })();
    

    그 결과 이제 3D 마인드 맵을 확대/축소, 회전 및 패닝할 수 있습니다. 정말 쉬웠습니다!



    여기에서 직접 사용해 보세요.


  • 확대/축소하려면 마우스 휠을 사용하십시오(Mac에서는 두 손가락 트랙패드를 위/아래로 스와이프)
  • .
  • 뷰포트를 이동(이동)하려면 마우스 오른쪽 버튼을 클릭하고 드래그합니다
  • .
  • 회전하려면 마우스 왼쪽 버튼을 클릭하고 드래그합니다
  • .

    좋아 보이지만 좋지는 않습니다!



    이 시점에서 여전히 저를 괴롭히는 것은 마인드맵을 회전할 때 마인드맵 노드 사이의 연결선이 노드와 겹치므로 텍스트 레이블을 읽기 어렵고 전체적으로 이상하게 보입니다.

    수정



    구조에 대한 StackOverflow:




    답변 재: Threejs로 객체의 zOrder를 변경하는 방법은 무엇입니까?



    10월 1일 '12


    80





    일부 개체를 "위"또는 "앞"에 렌더링하려면 한 가지 방법은 두 개의 장면을 만드는 것입니다. 첫 번째 장면은 일반 장면이고 두 번째 장면에는 맨 위에 두고 싶은 개체가 포함됩니다.
    먼저 설정
    renderer.autoClear = false;
    

    그런 다음 두 개의 장면을 만듭니다...




    Open Full Answer




    요령은 마인드 맵 노드 스프라이트(CSS의 Z-인덱스와 유사)의 renderOrder 속성을 조작한 다음 각 스프라이트가 렌더링되기 전에 렌더러에서 clearDepth을 호출하는 것입니다.

    다음은 내 함수에서 마인드 맵 노드를 렌더링하는 업데이트된 코드입니다renderMindMap.

    data.nodes = await Promise.all(
      data.nodes.map((node) =>
        renderToSprite(<MindMapNode label={node.name} level={node.level} />, {
          width: 128,
          height: 64
        }).then((sprite) => {
          sprite.renderOrder = 999;
          sprite.onBeforeRender = (renderer) => renderer.clearDepth();
          return { ...node, sprite };
        })
      )
    );
    


    이것은 원하는 효과가 있습니다. 마음의 내용에 맞게 마인드 맵을 회전할 수 있으며 연결선은 마인드 맵 노드와 겹치지 않습니다.



    시도해 보세요:



    계속하려면…



    저는 제 마인드맵을 소셜 미디어 네트워크 및 협업 도구로 전환할 계획이며 후속 기사에서 저의 진행 상황에 대해 계속 블로그에 올릴 것입니다. 계속 지켜봐!

    좋은 웹페이지 즐겨찾기