LoginSignup
1
1

More than 1 year has passed since last update.

Next.jsでめちゃらくに3DモデルをLoD

Posted at

初めに

今作ってるゲームエンジンの軽量化のために、
自動LODを制作しています。
Three.jsの公式フォーラムに聞いたところ、
@gltf-transform/coreが手っ取り早くていいぞとのことだったので、
さっそく使ってみました。

実行結果

image.png

Next.jsで記述

インストール

npm install @gltf-transform/core @gltf-transform/functions meshoptimizer

ソース

import type { NextApiRequest, NextApiResponse } from "next";
import { NodeIO } from "@gltf-transform/core";
import { simplify, weld } from '@gltf-transform/functions';
import { MeshoptSimplifier } from 'meshoptimizer';
import { basename, dirname } from "path";

/**
 * 自動LOD化API
 */
type FilePathList = {
  filePaths: { low: string, mid: string, high: string };
  error?: string;
}

const STORAGE_PATH = process.env.STORAGE_PATH;

// 指定ファイルをLODにする
export default async (req: NextApiRequest, res: NextApiResponse<FilePathList>) => {
  const { filePath } = req.query;
  if (req.method == "GET" && filePath) {
    const io = new NodeIO();
    const document = await io.read(
      `${STORAGE_PATH}/${filePath}`
    );
    const low = document.clone();
    const mid = document.clone();

    // 普通に削減
    await low.transform(
      weld({ tolerance: 0.01 }),
      simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.01 })
    );

    // 軽微な削減
    await mid.transform(
      weld({ tolerance: 0.0001 }),
      simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.0001 })
    );

    //保存
    const dirName = dirname(filePath as string);
    const fileName = basename(filePath as string).split(".")[0];
    const lowFileName = `${fileName}-low.glb`;
    await io.write(`${STORAGE_PATH}/${dirName}/${lowFileName}`, low);
    const midFileName = `${fileName}-mid.glb`;
    await io.write(`${STORAGE_PATH}/${dirName}/${midFileName}`, mid);

    res.status(200).json({ error: '', filePaths: { 
      low: `${dirName}/${lowFileName}`, 
      mid: `${dirName}/${lowFileName}`, 
      high: filePath.toString() 
    }});

  }
  else {
    res.status(400).json({ error: 'Error', filePaths: null });
  }
};

重要な部分はここ

import { NodeIO } from '@gltf-transform/core';
import { simplify, weld } from '@gltf-transform/functions';
import { MeshoptSimplifier } from 'meshoptimizer';

const io = new NodeIO();
const document = await io.read('path/to/model.glb');
const document2 = document.clone();

// 普通に削減
await document.transform(
  weld({ tolerance: 0.01 }),
  simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.01 })
);

// ちょこっと削減
await document2.transform(
  weld({ tolerance: 0.0001 }),
  simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.0001 })
);

めっちゃ簡単!

1
1
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
1
1