Link Search Menu Expand Document

OBJ

이 튜토리얼은 Three.js를 이용한 OBJ 파일을 이용한 3D 기반의 ARWebApp을 만드는 방법을 설명합니다.

Table of contents

  1. OBJ
  2. 준비사항
    1. three.js
    2. Letsee Web AR SDK
  3. 코드 설명
    1. js 임포트
    2. 증강을 위한 Entity 설정
    3. Web AR SDK 실행 및 three.js
    4. 라이트 생성
    5. 3D 오브젝트 로드
    6. three.js 코드
  4. What you should see
  5. Final code
  6. Demo

OBJ

지오메트리 파일 포맷으로 3D 모델 데이터를 저장하기 위한 파일 포맷입니다. 지오메트리의 Vertex 위치, UV 좌표, Vertex Normals, Face, Texture Vertex 좌표 정보를 포함합니다.

준비사항

three.js

아래의 예제는 three.js의 OBJ Loader 예제를 Letsee Web AR SDK에 맞추어 변환한 것 입니다.
3D파일을 로드하기 위한 스크립트, 3D 오브젝트 파일등은 three.js의 github에서 다운로드 받을 수 있습니다.

three.js는 r120 버전을 기준으로 설명합니다.

Letsee Web AR SDK

Web AR 어플리케이션에서 사용할 마커 이미지와 엔터티 설정 파일이 필요합니다. 아래 예제에서 사용한 마커와 엔터티 파일은 Letsee에서 제공하는 샘플 입니다.

Letsee Web AR SDK를 사용하기 위해서는 SDK파일과 appKey가 필요합니다. SDK 파일은 cdn을 통해 제공됩니다.
인증을 위한 appKey는 이곳을 확인해 주시기 바랍니다.


코드 설명

js 임포트

Letsee Web AR SDK와 three.js를 위한 javascript를 임포트 합니다.

three.js의 OBJ loading sample를 참고하여 OBJLoader.js를 준비합니다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.js"></script>
<script src="https://developer.letsee.io/api/webar?key=YOUR_APP_KEY"></script>
<script src="js/loaders/r120/OBJLoader.js"></script>

증강을 위한 Entity 설정

증강할 대상을 addTarget 이벤트의 매개변수로 설정합니다.

letsee.addTarget('letsee-marker.json').then(entity => {})

Web AR SDK 실행 및 three.js

letsee의 init 이벤트 실행, ready 이벤트의 callback에 start 이벤트를 등록하여 어플리케이션을 실행합니다.

letsee.ready(() => {
  letsee.start();
  letsee.addTHREE(THREE).then(obj => {
    renderer = obj.renderer;
    scene = obj.scene;
    initWorld(obj);
  })
});
letsee.init();

라이트 생성

렌더링을 위한 라이트를 생성합니다.

let ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
let pointLight = new THREE.PointLight( 0xffffff, 0.8 );
scene.add(ambientLight);
scene.add(pointLight);

3D 오브젝트 로드

OBJ Loader를 사용하여 3D 오브젝트를 로드하고 증강대상과의 정합을 위해 entity에 등록 후, scene에 entity를 등록합니다. 프레임 단위로 render합니다.

// Load model and add to entity
letsee.addTarget('letsee-marker.json').then(entity => {
  let toystory = entity;

  // load model
  function loadModel() {
    object.traverse( function ( child ) {
      if ( child.isMesh ) child.material.map = texture;
    } );
    object.position.y = - 95;
  }

  const manager = new THREE.LoadingManager( loadModel );
  manager.onProgress = function ( item, loaded, total ) {
    console.log( item, loaded, total );
  };

  const textureLoader = new THREE.TextureLoader(manager);
  const texture = textureLoader.load( 'textures/UV_Grid_Sm.jpg' );

  function onProgress( xhr ) {
    if ( xhr.lengthComputable ) {
      const percentComplete = xhr.loaded / xhr.total * 100;
      console.log( 'model ' + Math.round( percentComplete, 2 ) + '% downloaded' );
    }
  }

  function onError() {}

  const loader = new THREE.OBJLoader( manager );

  loader.load( 'models/obj/male02/male02.obj', function ( obj ) {
    object = obj;
    toystory.add(object);

    // Add entity to scene
    scene.add(toystory);

  }, onProgress, onError );

  // Render all
  const renderAll = async function() {
    requestAnimationFrame(renderAll);
    await letsee.threeRenderer().update(); // Engine mainLoop 수행
    const camera = letsee.threeRenderer().getDeviceCamera(); // 매 프레임마다 카메라 얻어옴.
    renderer.render(scene, camera);
  };
  renderAll();
});

three.js 코드

OBJ loading sample을 바탕으로한 3d 오브젝트 증강 예제 입니다.


What you should see






Final code

소스 코드는 이곳에서 다운받을 수 있습니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Letsee WebAR Demo</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.js"></script>
  <script src="https://developer.letsee.io/api/webar?key=YOUR_APP_KEY"></script>
  <script src="js/loaders/r120/OBJLoader.js"></script>
</head>
<body>
<div id="container"></div>
<script>
  let scene;
  let renderer;
  let object;
  let clock = new THREE.Clock();

  letsee.ready(() => {
    letsee.start();
    letsee.addTHREE(THREE).then(obj => {
      renderer = obj.renderer;
      scene = obj.scene;
      initWorld();
    })
  });
  letsee.init();

  function initWorld() {
    // Add lights
    let ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
    let pointLight = new THREE.PointLight( 0xffffff, 0.8 );
    scene.add(ambientLight);
    scene.add(pointLight);

    // Load model and add to entity
    letsee.addTarget('letsee-marker.json').then(entity => {
      let toystory = entity;

      // load model
      function loadModel() {
        object.traverse( function ( child ) {
          if ( child.isMesh ) child.material.map = texture;
        } );
        object.position.y = - 95;
      }

      const manager = new THREE.LoadingManager( loadModel );
      manager.onProgress = function ( item, loaded, total ) {
        console.log( item, loaded, total );
      };

      const textureLoader = new THREE.TextureLoader(manager);
      const texture = textureLoader.load( 'textures/UV_Grid_Sm.jpg' );

      function onProgress( xhr ) {
        if ( xhr.lengthComputable ) {
          const percentComplete = xhr.loaded / xhr.total * 100;
          console.log( 'model ' + Math.round( percentComplete, 2 ) + '% downloaded' );
        }
      }

      function onError() {}

      const loader = new THREE.OBJLoader( manager );

      loader.load( 'models/obj/male02/male02.obj', function ( obj ) {
        object = obj;
        toystory.add(object);

        // Add entity to scene
        scene.add(toystory);

      }, onProgress, onError );

      // Render all
      const renderAll = async function() {
        requestAnimationFrame(renderAll);
        await letsee.threeRenderer().update(); // Engine mainLoop 수행
        const camera = letsee.threeRenderer().getDeviceCamera(); // 매 프레임마다 카메라 얻어옴.
        renderer.render(scene, camera);
      };
      renderAll();
    });
  }
</script>
</body>
</html>

Demo

모바일 디바이스로만 확인 가능합니다.
Demo link