[21-06-06 TIL] html 태그를 Scene Object에 위치시키기

O2o2✨·2021년 6월 6일
0

TIL

목록 보기
7/20

HTML

<div id="container">
  <canvas id="c"></canvas>
  <div id="labels">
    <div id="label">이름표</div>
  </div>
</div>
  
  

CSS

html, body {
  height: 100%;
  margin: 0;
}
#c {
  width: 100%;  /* let our container decide our size */
  height: 100%;
  display: block;
}
#container {
  position: relative;  /* makes this the origin of its children */
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#labels {
  position: absolute;  /* let us position ourself inside the container */
  z-index: 0;          /* make a new stacking context so children don't sort with rest of page */
  left: 0;             /* make our position the top left of the container */
  top: 0;
  color: white;
}
#labels>div {
  white-space: nowrap;
  position: absolute;  /* let us position them inside the container */
  left: 0;             /* make their default position the top left of the container */
  top: 0;
  cursor: pointer;     /* change the cursor to a hand when over us */
  font-size: large;
}

JS

import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
import { OrbitControls } from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({ canvas });
  const camera = new THREE.OrthographicCamera(-50, 50, 50, -50, 0.001, 10000);
  const controls = new OrbitControls(camera, canvas);
  const scene = new THREE.Scene();

  // 큐브 생성  
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const material = new THREE.MeshBasicMaterial({ color: 0x00ffff });
  const cube = new THREE.Mesh(geometry, material);
  cube.position.x = 10;

  // 렌더링할 오브젝트를 묶는 group 생성
  const group = new THREE.Group();
  group.add(cube);
  scene.add(group);

  const borderBox = new THREE.Box3();
  borderBox.setFromObject(group); // group을 감싸는 borderBox
  let center = new THREE.Vector3();
  borderBox.getCenter(center); // borderBox의 센터값을 구해 center에 넣는다

  camera.position.set(center.x, center.y, 10); // 카메라를 borderBox의 센터에 위치시킴
  controls.target.set(center.x, center.y, 0); 
  controls.update(); 

  const label = document.querySelector('#label');
  const tempV = new THREE.Vector3();

  function render(time) {
    time *= 0.001;

    // ★★★★★★★★★★★★★★★★★★
    // 큐브의 센터 포지션을 얻는다.
    cube.updateWorldMatrix(true, false);
    cube.getWorldPosition(tempV);

    // 정규화된 스크린 좌표를 얻는다
    // x와 y는 -1 ~ 1 사이 범위에 있다.
    // x = -1이면 왼쪽, y = -1이면 아래쪽이다.
    tempV.project(camera);

    // 정규화(normalized)된 포지션을 CSS 좌표로 변환
    const x = (tempV.x * .5 + .5) * canvas.clientWidth;
    const y = (tempV.y * -.5 + .5) * canvas.clientHeight;

    // label 엘리먼트를 해당 포지션으로 이동
    label.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;   
    // ★★★★★★★★★★★★★★★★★★

    renderer.render(scene, camera);
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}

main();

참고

profile
리액트 프론트엔드 개발자입니다.

0개의 댓글