2. FrontEnd/Three.js / / 2023. 11. 27. 16:41

[R3F] Next에 R3F 적용하고, Text 넣는 방법

728x90

문제

Next@13.2.0버전에 @react-three/fiber^8.15.11, @react-three/drei^9.88.17, three^0.158.0을 적용하고,

다음 코드와 같이 텍스트를 Canvas에 감싸면 렌더링 되겠지 했더니 다음과 같은 에러가 난다.

<main style={{ width: '100vw', height: '100vh' }}>
  <Canvas
    camera={{
     position: [10000, 10000, 10000],
     rotation: [-0.5, 0, 0],
     far: 100000,
    }}
  >
   <color attach="background" args={['#000']} />
   <ambientLight color={'#fff'} intensity={5} />
   <OrbitControls />
   이렇게 텍스트 넣으려고 했는데, 오류남

  </Canvas>
  {children}
</main>
Text is not allowed in the R3F tree! This could be stray whitespace or characters.

 

해결방법1

다음과 같은 Text컴포넌트를 만들어서, json으로 된 폰트를 지정하여 텍스트 렌더링하는 방법

// Import necessary dependencies
import { useEffect, useMemo } from 'react';
import * as THREE from 'three';
import { useLoader, useThree } from '@react-three/fiber';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';

// Create a Text component
const Text = ({ children, ...props }: any) => {
  const { size = 1, color = '#000000', ...restProps } = props;

  const { camera } = useThree();

  // Load a font (you can replace 'path/to/your/font.json' with the actual path)
  const font = useLoader(FontLoader, '/fonts/KimjungchulGothic.json');

  // Calculate size based on camera position
  const calculatedSize = useMemo(() => {
    const distance = camera.position.distanceTo(new THREE.Vector3(0, 0, 0));
    return (size * distance) / 1000; // Adjust the divisor as needed
  }, [size, camera.position]);

  // Create text geometry
  const geometry = useMemo(() => {
    const textGeometry = new TextGeometry(children, {
      font,
      size: calculatedSize,
      height: 0.1, // Adjust as needed
      curveSegments: 12,
      bevelEnabled: false,
    });
    textGeometry.center();
    return textGeometry;
  }, [children, font, calculatedSize]);

  return (
    <mesh {...restProps} geometry={geometry}>
      <meshStandardMaterial color={color} />
    </mesh>
  );
};

export default Text;

나는 위와 같은 방식으로 하면, 원래 했던 코드들을 저런식으로 모두 바꿔야해서 다음 방법을 사용함

 

해결방법2

css로 position: absolute를 지정하여 상단으로 끌어올리는것

'use client';
import React from 'react';
import styled from 'styled-components';

export const AbsolDiv = styled.div`
  display: flex;
  position: absolute;
  flex-direction: row;
  top: 100px;
  left: 50%;
  transform: translate(-50%, 0%);
`;

나는 styled component를 사용해서 common이라고 만들고 그안에 저렇게 정의한 후, 다음과같이 사용했다.

'use client';
import { AbsolDiv } from '../../_components/common';
import PageHeader from '../../_components/pageHeader';
import PortfolioMain from './portfolioMain';
import PortfolioMini from './portfolioMini';

export default function Page() {
  return (
    <AbsolDiv className="projects">
      <main>
        <PageHeader titleBg="Projects">
          My <span className="point">Projects</span>
        </PageHeader>
        <section>
          <PortfolioMain />
          <PortfolioMini />
        </section>
      </main>
    </AbsolDiv>
  );
}

 

결과 완성본 두둥!!

'2. FrontEnd > Three.js' 카테고리의 다른 글

[Three.js] R3F(React Three Fiber)  (1) 2023.11.21
Three.js (01. 정의, 구조 및 개념)  (0) 2023.05.23
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유