LoginSignup
14
6

More than 1 year has passed since last update.

React (TypeScript) で WebAR する

Posted at

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 は、そのうち勉強する。

14
6
0

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
  3. You can use dark theme
What you can do with signing up
14
6