LoginSignup
6

posted at

React (TypeScript) で WebAR する

model-viewer

簡単に WebAR する Google 製のライブラリの model-viewer を React で使いたかったが、思いの外まとまった資料が少なく苦労した。ので、メモ。

結論

ModelViewer.tsx
/** @jsxImportSource @emotion/react */
import { FC } from 'react';
import { css } from '@emotion/react';
import '@google/model-viewer';
declare global {
  namespace JSX {
    interface IntrinsicElements {
      'model-viewer': MyElementAttributes;
    }
    interface MyElementAttributes {
      src: string;
      poster: string;
      alt: string;
      ar: boolean;
      scale: string;
    }
  }
}

type Props = {
  poster: string;
  glb: string;
  usdz: string;
  alt: string;
  scale?: number;
  height?: string;
};
export const ModelViewer: FC<Props> = (props) => {
  const { poster, glb, usdz, alt, scale = 1, height = '80vh' } = props;

  const container = css`
    width: 100%;
    model-viewer {
      width: 100%;
      height: ${height};
    }
  `;

  return (
    <div css={container}>
      <model-viewer
        src={glb}
        ios-src={usdz}
        poster={poster}
        alt={alt}
        shadow-intensity="1"
        camera-controls
        ar
        scale={`${scale} ${scale} ${scale}`}
      ></model-viewer>
    </div>
  );
};

Screen Shot 2022-12-20 at 16.25.58.png
SP Browser AR Mode

環境

  • react: 18.2.0
  • @google/model-viewer: 2.1.1
  • @emotion/react: 11.10.5
  • node: 16.15.1

mode-viewer を埋め込む

<model-viewer></model-viewer> を埋め込もうとすると、Property 'model-viewer' does not exist on type 'JSX.IntrinsicElements'. と怒られてしまう。そこで、

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'model-viewer': MyElementAttributes;
    }
    interface MyElementAttributes {
      src: string;
      poster: string;
      alt: string;
      ar: boolean;
      scale: string;
    }
  }
}

こんな風に宣言してあげる必要がある。MyElementAttributes に書いているのは、- の入っていないパラメータだ。人によって設定は違うと思うので、怒られながら設定すれば良い。

表示がちっちゃい

デフォルトだと Canvas が、ものすごく小さく表示されてしまうので、画面いっぱいに大きくする。

    model-viewer {
      width: 100%;
      height: ${height};
    }

CSS の与え方は何でも良いが、<model-viewer> という要素に、幅と高さを付ける。今回、幅も高さも画面いっぱい使いたかったのだが、スマートフォンで見た時に、下の方がちょっと切れちゃって、AR ボタンが押せなかったので、80vh になっている。が、表示したいサイズに合わせて設定。

表示がでっかい

AR Mode

読み込む 3D Model のサイズによるんだろうと思いつつ、AR Mode にした時に、表示される大きさがでかすぎて使いづらい。
そこで、model-viewerscale を設定する。

      <model-viewer
        src={glb}
        ios-src={usdz}
        poster={poster}
        alt={alt}
        shadow-intensity="1"
        camera-controls
        ar
        scale={`${scale} ${scale} ${scale}`}
      ></model-viewer>

ar-scale="fixed" にしていると scale は1(100%)固定のようだ。android と iOS で大きさが違うので、なんだか微妙だが、WebAR で使う 3D Model のポリゴン数には制限があって、それ用に作ると思うので、元を良い感じのサイズで作ってくれ。ということで。

ちょうどカメラのフレーム内に収まるように表示する方法はないものか…

Local のテストでスマホのカメラにアクセスする

$ HTTPS=true yarn start
---
Compiled successfully!

You can now view model3d in the browser.

  Local:            https://localhost:3000
  On Your Network:  https://192.168.1.8:3000

Note that the development build is not optimized.
To create a production build, use yarn build.

webpack compiled successfully
Files successfully emitted, waiting for typecheck results...
Issues checking in progress...
No issues found.

https でないと、カメラアクセスはできないので、HTTPS=true で立ち上げ、On Your Network: に表示されている 192.168... にアクセスする。

おしまい

最近、3D Model を表示して、WebAR したいみたいな案件は、結構多い。
Three.js は、そのうち勉強する。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
6