Translations: Japanese

Get started (Three.js)

This is a brief introduction to how to incorporate VerseEngine using Three.jsopen in new window and VerseEngine's simple library verse-three.

Alternatively, you can download the complete source code from here (github.com)open in new window.

Step 0: Create the world

First, create a simple space in Three.js.
For more information, see the Manual for Three.jsopen in new window.

View source code
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1,viewport-fit=cover"/>
  <style> body { margin: 0; overflow: hidden; }</style>
  <script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/es-module-shims.min.js"></script>
  <script type="importmap">
    {
      "imports": {
        "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
        "three/examples/jsm/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
        "./index": "./index.js"
      }
    }
  </script>
  <script type="module">
    import * as App from "./index";
  </script>
</head>
<body></body>
</html>
import * as THREE from "three";
import { Sky } from "three/examples/jsm/objects/Sky.js";

function setupScene() {
  const renderer = new THREE.WebGLRenderer();
  renderer.outputEncoding = THREE.sRGBEncoding;
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  document.body.appendChild(renderer.domElement);

  window.addEventListener("resize", () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });

  const scene = new THREE.Scene();

  const camera = new THREE.PerspectiveCamera(
    60,
    window.innerWidth / window.innerHeight,
    0.1,
    100
  );
  camera.position.set(0.0, 1.6, 0);
  scene.add(camera);

  scene.add(new THREE.AmbientLight(0xffffff, 1.0));

  {
    const sky = new Sky();
    sky.scale.setScalar(450000);
    scene.add(sky);

    const sun = new THREE.Vector3();
    sun.setFromSphericalCoords(
      1,
      THREE.MathUtils.degToRad(60),
      THREE.MathUtils.degToRad(180)
    );
    sky.material.uniforms["sunPosition"].value.copy(sun);
  }
  let ground;
  {
    ground = new THREE.Mesh(
      new THREE.PlaneGeometry(50, 50, 1, 1),
      new THREE.MeshLambertMaterial({
        color: 0x5e5e5e
      })
    );
    ground.rotation.x = Math.PI / -2;
    scene.add(ground);
  }
  scene.add(new THREE.GridHelper(50, 50));

  const animate = () => {
    renderer.render(scene, camera);
  };
  renderer.setAnimationLoop(animate);
}

function main() {
  setupScene();
}

main();

Step 1: Extend setupScene

Modify the setupScene.

  1. Enables functions to be specified externally to be executed every frame.
  2. Returns variables such as Scene.
...
/**
* @param {Array<(number)=>void>} ticks - Array of functions to be executed every frame
*/
function setupScene(ticks) {
  ...

  ticks ||= [];
  const clock = new THREE.Clock();
  const animate = () => {
    const dt = clock.getDelta();
    ticks.forEach((f) => f(dt));
    renderer.render(scene, camera);
  };
  renderer.setAnimationLoop(animate);

  return { scene, renderer, camera, ground};
}
function main() {
  const ticks = [];
  const { scene, renderer, camera, ground } = setupScene(ticks);
}
...

Step 2: Set up players and objects

...
function main() {
  const ticks = [];
  const { scene, renderer, camera, ground } = setupScene(ticks);

  // Create Player
  const cameraContainer = new THREE.Object3D(); // Head
  cameraContainer.add(camera);
  const player = new THREE.Object3D(); // Player Body
  player.add(cameraContainer);
  scene.add(player);
  camera.position.set(0.0, 1.6, 0); // Set camera position to default head height

  // Target to teleport with VR controller
  const teleportTargetObjects = [ground];
  // Ground and Obstacles
  const collisionBoxes = [new THREE.Box3().setFromObject(ground)];
}
...




 
 
 
 
 
 
 
 
 
 
 
 



Step 3: Load VerseEngine

Load the ES Modules version of verse-three and the tree-vrmopen in new window used inside the verse-three.

...
<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
      "three/examples/jsm/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
      "@pixiv/three-vrm": "https://cdn.jsdelivr.net/npm/@pixiv/[email protected]/lib/three-vrm.module.min.js",
      "verse-three": "https://cdn.jsdelivr.net/npm/@verseengine/[email protected]/dist/esm/index.min.js",
      "./index": "./index.js"
    }
  }
</script>
...





 
 






Step 4: Connect with VerseEngine

You can prepare your own animation and avatar files, though, You can also download verse-three exampleopen in new window and try it out quickly.

setup-verse.js

import * as VerseThree from "verse-three";
const VERSE_WASM_URL =
  "https://cdn.jsdelivr.net/npm/@verseengine/[email protected]/dist/verse_core_bg.wasm";
const ENTRANCE_SERVER_URL = "https://entrance.verseengine.cloud";
// Animation files
const ANIMATION_MAP = {
  idle: "./asset/animation/idle.fbx",
  walk: "./asset/animation/walk.fbx",
};
// Avatar files
const range = (n) => [...Array(n).keys()];
export const PRESET_AVATARS = [
  ...range(3).map((i) => `f${i}`),
  ...range(3).map((i) => `m${i}`),
].map((n) => ({
  thumbnailURL: `./asset/avatar/${n}.png`,
  avatarURL: `./asset/avatar/${n}.vrm`,
}));
const DEFAULT_AVATAR_URL =
  PRESET_AVATARS[Math.floor(Math.random() * PRESET_AVATARS.length)].avatarURL;
// WebRTC RTCIceServers
const ICE_SERVERS = [
  { urls: "stun:stun.l.google.com:19302" },
  { urls: "stun:stun1.l.google.com:19302" },
];

export const setupVerse = async (
  scene, renderer, camera, cameraContainer, player,
  collisionBoxes, teleportTargetObjects
) => {
  const adapter = new VerseThree.DefaultEnvAdapter(renderer, scene,
    camera, cameraContainer, player,
    () => collisionBoxes,
    () => [], // Wall or other obstacle (not specified in this case)
    () => teleportTargetObjects,
    isLowSpecMode: true, // Improve performance by omitting hair and other shaking
  );
  const mayBeLowSpecDevice = VerseThree.isLowSpecDevice();
  const res = await VerseThree.start(adapter, scene,
    VERSE_WASM_URL, ENTRANCE_SERVER_URL, DEFAULT_AVATAR_URL,
    ANIMATION_MAP, ICE_SERVERS,
    {
      maxNumberOfPeople: mayBeLowSpecDevice ? 8 : 16,
      maxNumberOfParallelFileTransfers: mayBeLowSpecDevice ? 1 : 4,
      presetAvatars: PRESET_AVATARS,
    }
  );
  return res.tick; // Return functions that need to be executed every frame
};

index.html

...
<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
      "three/examples/jsm/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
      "@pixiv/three-vrm": "https://cdn.jsdelivr.net/npm/@pixiv/[email protected]/lib/three-vrm.module.min.js",
      "verse-three": "https://cdn.jsdelivr.net/npm/@verseengine/[email protected]/dist/esm/index.min.js",
      "./setup-verse": "./setup-verse.js",
      "./index": "./index.js"
    }
  }
</script>
...







 






index.js

...
import { setupVerse } from "./setup-verse";
...


function main() {
  const ticks = [];
  const { scene, renderer, camera, ground } = setupScene(ticks);

  // Create Player
  const cameraContainer = new THREE.Object3D(); // Head
  cameraContainer.add(camera);
  const player = new THREE.Object3D(); // Player Body
  player.add(cameraContainer);
  scene.add(player);
  camera.position.set(0.0, 1.6, 0); // Set camera position to default head height

  // Target to teleport with VR controller
  const teleportTargetObjects = [ground];
  // Ground and Obstacles
  const collisionBoxes = [new THREE.Box3().setFromObject(ground)];

  setupVerse(
    scene, renderer, camera, cameraContainer, player, 
    collisionBoxes, teleportTargetObjects
  ).then((tick) => {
    ticks.push(tick);
  });
}
...
 




















 
 
 
 
 
 



For more detailed usage, see verse-three referenceopen in new window.

Tips

WARNING

VerseEngine builds a network of users for each web page URL.
When using localhost or local IP (e.g. 192.168.xxx.xxx) for development, some URLs may connect to strangers.
Either assign a dedicated name to the IP address in the hosts file,
Alternatively, you can work around it by giving the html file a sufficiently long random filename.

# https://very-long-name12345678/
127.0.0.1 very-long-name12345678

TIP

To use all functions, you must communicate via HTTPS.

Examples of services that can easily support HTTPS for web servers

Tools to create local development certificates

Example of starting HTTPS Server for local development on Mac

# Install mkcert using Homebrew
brew install mkcert
mkcert -install
# Create a certificate (change the IP address to match your environment)
mkdir cert
cd cert
mkcert localhost 127.0.0.1 192.168.10.2
cd ..
# Start the server
npx http-server -c-1 --ssl --key ./cert/localhost+2-key.pem --cert ./cert/localhost+2.pem -p 8080
Last Updated: