mcpField
T
threejs-fundamentals

threejs-fundamentals

github.com/cloudai-x開発3.8k18.2k 回インストール1 週間前に更新
リポジトリ

threejs-fundamentals について

threejs-fundamentals は、three.js r186 の基本概念とAPIを解説するリファレンススキルです。シーン、カメラ、オブジェクト、レンダリング、数学ツール、リソース管理、性能、WebGPU/TSLを扱います。

主な機能

  1. 01シーン、カメラ、レンダラー
  2. 02Object3D、グループ、メッシュ
  3. 03座標、ベクトル、行列
  4. 04読み込み管理とリソース解放
  5. 05性能とフラスタムカリング
  6. 06WebGPUとTSLの基礎

活用シーン

  1. 01three.jsのシーンとカメラの構築
  2. 02WebGLRendererまたはWebGPURendererの設定
  3. 03ジオメトリのカリングや描画負荷の調査
  4. 04読み込み状況の管理とリソース解放

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-fundamentals

インストール後、Claude Code で/threejs-fundamentalsを入力して読み込まれたか確認します。

詳細

Three.js の基礎

three.js r186 を対象としています。例では WebGLRenderer を使用します。WebGPU と TSL のセクションでは WebGPURenderer を使用します。

クイックスタート

import * as THREE from "three";

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111318);

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 1.5, 5);

const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshStandardMaterial({ color: 0x3a86ff }),
);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(3, 4, 5); // shines from its position toward the origin
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.4));

const timer = new THREE.Timer();
timer.connect(document); // freezes the delta while the tab is hidden

function animate() {
  timer.update(); // advance the timer first thing each frame
  cube.rotation.y += timer.getDelta(); // seconds since the previous frame
  renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);

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

バンドラーを使用しない場合、ブラウザーはインポートマップを介して three.js を ES モジュールとして読み込みます。以下は、上記の WebGLRenderer の例で使用するマップです。

<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
  }
}
</script>

WebGPURenderer を使用する場合は、4 つのキーすべてをマッピングしてください。three.tsl.js は three/webgpu をインポートするため、そのエントリーがないとマップは機能しません。

<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.webgpu.js",
    "three/webgpu": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.webgpu.js",
    "three/tsl": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.tsl.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
  }
}
</script>

シーン

const scene = new THREE.Scene();

scene.background = new THREE.Color(0x111318); // solid color
scene.fog = new THREE.Fog(0x111318, 1, 100); // linear fog: near, far
scene.fog = new THREE.FogExp2(0x111318, 0.02); // exponential fog: density (pick one)
  • scene.background には CubeTexture、または mapping が THREE.EquirectangularReflectionMapping の Texture も指定できます。マッピングされていない通常のテクスチャは、スカイボックスではなく、画面全体を覆う平面として描画されます。
  • scene.environment は、両方のレンダラーで MeshStandardMaterial と MeshPhysicalMaterial を、WebGLRenderer でのみ MeshLambertMaterial と MeshPhongMaterial を照らします。scene.environmentIntensity で強度を調整できます。material.envMapIntensity が調整するのは material.envMap のみです。HDR 環境については threejs-loaders を参照してください。

カメラ

PerspectiveCamera
// PerspectiveCamera(fov in degrees, aspect, near, far)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0); // rotates the camera to face the target

camera.fov = 60;
camera.updateProjectionMatrix(); // required after changing fov, aspect, near or far
OrthographicCamera
// OrthographicCamera(left, right, top, bottom, near, far); frustum size in world units
const aspect = window.innerWidth / window.innerHeight;
const frustumHeight = 10;
const camera = new THREE.OrthographicCamera(
  (-frustumHeight * aspect) / 2,
  (frustumHeight * aspect) / 2,
  frustumHeight / 2,
  -frustumHeight / 2,
  0.1,
  1000,
);
// on resize: recompute left and right from the new aspect, then call camera.updateProjectionMatrix()
ArrayCamera
// Renders the scene once per sub-camera, each into its own viewport.
// Viewport units under WebGLRenderer are drawing-buffer pixels (CSS size × pixel ratio);
// WebGPURenderer multiplies CSS pixels by the pixel ratio itself.
const width = window.innerWidth;
const height = window.innerHeight;
const dpr = renderer.getPixelRatio();
const cameras = [];
for (let i = 0; i < 4; i++) {
  const subCamera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
  subCamera.viewport = new THREE.Vector4(
    ((i % 2) * width * dpr) / 2,
    (Math.floor(i / 2) * height * dpr) / 2,
    (width * dpr) / 2,
    (height * dpr) / 2,
  );
  subCamera.position.set(-2 + (i % 2) * 4, 1.5, 6);
  subCamera.lookAt(0, 0, 0);
  subCamera.updateMatrixWorld(); // sub-cameras are not scene-graph children; update them when they move
  cameras.push(subCamera);
}
const arrayCamera = new THREE.ArrayCamera(cameras);
arrayCamera.position.set(0, 1.5, 6); // WebGLRenderer culls every viewport with this camera's frustum (fov 50, aspect 1 by default); WebGPURenderer uses each sub-camera's frustum
renderer.render(scene, arrayCamera);
CubeCamera
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256);
const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
scene.add(cubeCamera);

const chrome = new THREE.Mesh(
  new THREE.SphereGeometry(1, 32, 16),
  new THREE.MeshStandardMaterial({ color: 0xffffff, metalness: 1, roughness: 0 }),
);
chrome.material.envMap = cubeRenderTarget.texture;
scene.add(chrome);

// every frame: hide the reflective mesh, or it is drawn into the map it samples
chrome.visible = false;
cubeCamera.position.copy(chrome.position);
cubeCamera.update(renderer, scene);
chrome.visible = true;

WebGPURenderer では、WebGLCubeRenderTarget の代わりに three/webgpu の CubeRenderTarget でターゲットを構築します。

WebGLRenderer

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector("#canvas"), // reuse an existing canvas; omit to create one
  antialias: true, // MSAA
  alpha: true, // let the page background show through the canvas
  stencil: true, // stencil is off by default; pass this for stencil techniques
  powerPreference: "high-performance",
  preserveDrawingBuffer: true, // keep the drawing buffer for readPixels / screenshots
});

renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // cap the fill rate on high-DPI displays
renderer.setSize(window.innerWidth, window.innerHeight);

renderer.toneMapping = THREE.ACESFilmicToneMapping; // or AgXToneMapping, NeutralToneMapping; NoToneMapping is the default
renderer.toneMappingExposure = 1.0;
// renderer.outputColorSpace is SRGBColorSpace by default; leave it alone

renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap; // the default, already soft; VSMShadowMap and BasicShadowMap are the alternatives

renderer.setClearColor(0x000000, 0); // clear alpha 0 keeps the alpha: true canvas transparent
renderer.render(scene, camera);

オブジェクト

Object3D

Mesh、Group、Light、Camera の基底クラスです。

const obj = new THREE.Object3D();
const child = new THREE.Object3D();

obj.position.set(1, 2, 3); // translation
obj.rotation.set(0, Math.PI / 4, 0); // Euler angles in radians; kept in sync with quaternion
obj.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4); // the same rotation as a quaternion
obj.scale.set(1, 1, 1);

obj.getWorldPosition(new THREE.Vector3()); // world-space queries take a target vector to write into
obj.getWorldQuaternion(new THREE.Quaternion());
obj.getWorldDirection(new THREE.Vector3()); // the +Z axis in world space; cameras return their view direction (−Z)

obj.add(child); // reparents child; also removes it from its previous parent
obj.attach(child); // reparents and keeps child's world transform; add() keeps the local one
obj.remove(child);
obj.visible = false; // hides the whole subtree

obj.layers.enable(1); // ADD layer 1; set(1) would replace the mask and leave layer 0
obj.layers.disable(1);
obj.layers.test(camera.layers); // true when the object shares a layer with the camera

obj.traverse((descendant) => {
  if (descendant.isMesh) descendant.castShadow = true; // visits obj itself, then all descendants
});

// matrix updates run automatically while matrixAutoUpdate is true (the default)
obj.matrixAutoUpdate = false;
obj.updateMatrix(); // composes obj.matrix and flags the world matrix dirty
// when writing obj.matrix directly instead, flag the world matrix yourself:
obj.matrixWorldNeedsUpdate = true;
Group と Mesh
const group = new THREE.Group(); // an Object3D that exists to hold children
const ball = new THREE.Mesh(new THREE.SphereGeometry(0.5), new THREE.MeshStandardMaterial());
group.add(ball);
group.rotation.y = Math.PI / 4; // transforms the whole subtree
scene.add(group);
const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial());
scene.add(mesh);

// one material per geometry group; BoxGeometry has six (+x, −x, +y, −y, +z, −z)
// a group whose materialIndex has no material is not drawn
const faceColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
const dice = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  faceColors.map((color) => new THREE.MeshStandardMaterial({ color })),
);

mesh.castShadow = true; // this object casts shadows
mesh.receiveShadow = true; // this object shows shadows
mesh.frustumCulled = true; // default: skipped when its bounding sphere leaves the camera frustum
mesh.renderOrder = 10; // renders later within the same transparency bucket

座標系

右手系で、+Y が上です。+X は右、+Y は上、+Z は視点側を向きます。原点にあり、回転していないカメラは −Z 方向を向きます。

const axesHelper = new THREE.AxesHelper(5); // red X, green Y, blue Z; 5 = axis length
scene.add(axesHelper);

数学ユーティリティ

Vector3
const a = new THREE.Vector3(1, 0, 0);
const b = new THREE.Vector3(0, 1, 0);
const c = a.clone(); // new vector with the same values

a.copy(b); // a becomes b
a.add(b); // in place: a = a + b
a.sub(b);
a.multiplyScalar(2);
a.divideScalar(2);
a.lerp(b, 0.5); // move halfway toward b
a.normalize(); // unit length
a.negate();
a.cross(b); // cross product, written into a (right-hand rule)

const len = a.length();
const lenSq = a.lengthSq(); // compare lengths without a square root
const dist = a.distanceTo(b);
const dot = a.dot(b); // > 0 same half-space, < 0 opposite, 0 perpendicular
const angle = a.angleTo(b); // radians

a.applyQuaternion(new THREE.Quaternion());
a.applyMatrix4(new THREE.Matrix4());
a.project(camera); // world position to normalized device coordinates
a.unproject(camera); // normalized device coordinates back to world
Matrix4、Quaternion、Euler
const m = new THREE.Matrix4();
m.identity();
m.makeTranslation(1, 2, 3);
m.makeRotationY(Math.PI / 4);
m.makeScale(2, 2, 2);

const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3(1, 1, 1);
m.compose(position, quaternion, scale); // build from transform components
m.decompose(position, quaternion, scale); // read them back

m.multiply(new THREE.Matrix4()); // m = m * other (other applied first)
m.premultiply(new THREE.Matrix4()); // m = other * m
m.invert();
m.lookAt(new THREE.Vector3(0, 0, 1), new THREE.Vector3(), new THREE.Vector3(0, 1, 0)); // eye, target, up

const q = new THREE.Quaternion();
q.setFromEuler(new THREE.Euler(0, Math.PI / 2, 0, "YXZ")); // Euler order matters, XYZ is the default
q.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4);
q.setFromRotationMatrix(m);
q.slerp(new THREE.Quaternion(), 0.5); // spherical interpolation, written into q
q.invert();
Color
const color = new THREE.Color(0xff0000); // hex number
const sky = new THREE.Color("#87ceeb"); // also color names and "rgb(255, 0, 0)"

color.setHex(0x0000ff);
color.setRGB(1, 0.5, 0); // 0–1 in the linear working color space; hex and CSS strings are sRGB
color.setRGB(1, 128 / 255, 0, THREE.SRGBColorSpace); // sRGB components, the same color as 0xff8000
color.setHSL(0.5, 1, 0.5); // hue, saturation, lightness in 0–1, also linear unless a color space is passed
color.lerp(sky, 0.5); // interpolate toward the target, written into color
color.multiplyScalar(2); // scale the components
MathUtils
const clamped = THREE.MathUtils.clamp(15, 1, 10); // 10
const mixed = THREE.MathUtils.lerp(0, 10, 0.5); // 5
const mapped = THREE.MathUtils.mapLinear(0.5, 0, 1, 0, 100); // 50
const radians = THREE.MathUtils.degToRad(90);
const degrees = THREE.MathUtils.radToDeg(Math.PI);
const random = THREE.MathUtils.randFloat(1, 10);
const eased = THREE.MathUtils.smoothstep(0.5, 0, 1); // eased 0–1 curve

ローディングマネージャー

const manager = new THREE.LoadingManager();
manager.onStart = (url, loaded, total) => console.log(`started ${url}`);
manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total} ${url}`);
manager.onLoad = () => console.log("all items loaded");
manager.onError = (url) => console.error(`failed ${url}`);

const loader = new THREE.TextureLoader(manager); // any loader takes a manager

クリーンアップ

scene.remove(mesh);
// dispose geometry, materials and textures only when nothing else still uses them
mesh.geometry.dispose();
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
for (const material of materials) {
  for (const value of Object.values(material)) {
    if (value?.isTexture) value.dispose(); // material.dispose() leaves its textures alone
  }
  material.dispose();
}
mesh.dispose(); // frees renderer state kept for this object only

renderer.setAnimationLoop(null); // stop the loop
renderer.dispose(); // frees the renderer's GPU resources; the WebGL context stays alive
renderer.forceContextLoss(); // also release the context when the canvas is discarded

Object3D.dispose() はオブジェクトごとのレンダラー状態(WebGPURenderer のバインディング、WebGLRenderer のインスタンス化メッシュのバッファー)を解放しますが、子を走査したり、ジオメトリ、マテリアル、テクスチャを解放したりはしません。サブツリーを破棄するには、traverse で走査し、上記のように各メッシュを破棄してください。dispose() をオーバーライドするカスタム Object3D サブクラスでは、super.dispose() を呼び出してください。timer.dispose() は接続されたタイマーを切断します。

パフォーマンス

  • 視錐台カリングではバウンディングボックスではなく、バウンディングスフィアをテストします。通常のメッシュでは geometry.boundingSphere、InstancedMesh、SkinnedMesh、BatchedMesh ではオブジェクト自身の boundingSphere が対象です。どちらも一度だけ計算されるため、位置を編集した後は geometry.computeBoundingSphere() を呼び出してください。また、インスタンスやボーンを開始位置から遠くへ移動した後は object.computeBoundingSphere() を呼び出してください。そうしないと、表示対象のオブジェクトがカリングされます。
  • マテリアルを共有する静的ジオメトリは 1 つのメッシュに統合し、同じオブジェクトを多数複製する場合は InstancedMesh を使用してください(threejs-geometry)。
  • LOD を使って距離に応じてメッシュを切り替えます。レンダラーが毎フレーム update(camera) を呼び出します。
  • WebGLRenderer では、renderer.info.render.calls は直近の render() 呼び出しのドローコール数をカウントします(1 フレームに複数のパスがある場合は、renderer.info.autoReset = false を設定し、フレームごとに一度 renderer.info.reset() を呼び出してください)。また、renderer.info.memory は使用中のジオメトリとテクスチャの数を示します。メッシュの統合後やオブジェクトの破棄後に確認してください。
import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js";

// inputs must carry the same set of attributes
const merged = BufferGeometryUtils.mergeGeometries([
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.SphereGeometry(1, 32, 16),
]);

const lod = new THREE.LOD();
lod.addLevel(new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16)), 0); // distance 0: full detail
lod.addLevel(new THREE.Mesh(new THREE.SphereGeometry(1, 12, 8)), 20);
lod.addLevel(new THREE.Mesh(new THREE.SphereGeometry(1, 6, 4)), 60);
scene.add(lod);

WebGPU と TSL

import * as THREE from "three/webgpu";

const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init(); // must complete before any other use of the renderer
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111318); // the WebGPU canvas is transparent by default

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 1.5, 5);

const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshStandardNodeMaterial({ color: 0x3a86ff }),
);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(3, 4, 5); // shines from its position toward the origin
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.4));

const timer = new THREE.Timer();
timer.connect(document);

function animate() {
  timer.update();
  cube.rotation.y += timer.getDelta();
  renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
  • renderer.render() は、await renderer.init() が完了するまで例外をスローします。setAnimationLoop でも初期化されますが、セットアップコードがレンダラーに触れる前に、生成直後に init() を await してください。WebGL 2 フォールバックでは、init() 中に renderer.backend が置き換えられるためです。
  • WebGPU を利用できない場合、WebGPURenderer は自動的に WebGL 2 にフォールバックします。new THREE.WebGPURenderer({ forceWebGL: true }) でフォールバックを強制でき、await renderer.init() の後に renderer.backend.isWebGPUBackend を参照すると、実行中のバックエンドを確認できます。
  • ノードマテリアルと TSL は、どちらのバックエンドでも WebGPURenderer を対象とします。WebGLRenderer でこれらをレンダリングするには、WebGLNodesHandler アドオン(three/addons/tsl/WebGLNodesHandler.js を指定して renderer.setNodesHandler() に渡します)が必要です。これは移行支援用で、VSM シャドウ、MRT、トランスミッション、WebGPU のポストプロセッシングスタックには対応していません。ShaderMaterial と onBeforeCompile は WebGLRenderer 専用です。カスタムシェーディングを始める場合は threejs-shaders をご覧ください。
  • MeshStandardMaterial などの組み込みマテリアルは、ノード版に自動的に変換されます。ノードスロットを設定する場合は、*NodeMaterial クラスを使用してください。
  • ここには renderer.capabilities オブジェクトはありません。異方性は renderer.getMaxAnisotropy() で取得します。
  • GPU の読み戻しは引き続き非同期です。await renderer.getArrayBufferAsync(attribute) を使用してください。

よくある間違い

  • renderer.shadowMap.type = THREE.PCFSoftShadowMap → renderer.shadowMap.type = THREE.PCFShadowMap:r182で非推奨になりました。どちらのレンダラーも警告を出してPCFShadowMapにフォールバックします。PCFShadowMapはすでにソフトシャドウです。
  • const clock = new THREE.Clock() → const timer = new THREE.Timer(); timer.connect(document);:Clockはr183で非推奨になり、生成時に警告が出ます。timer.getDelta()またはtimer.getElapsed()を呼び出す前に、フレームごとに一度timer.update()を呼び出してください。
  • requestAnimationFrame(animate) → renderer.setAnimationLoop(animate):両方のレンダラーのドキュメントで、手動ループよりこちらが推奨されています。WebXRのフレームはこれを通じてのみ実行され、WebGPURendererではsetAnimationLoopが行う非同期初期化の前にrender()を呼び出すと例外が発生します。
  • subCamera.viewport = new THREE.Vector4(0, 0, 0.5, 0.5) → subCamera.viewport = new THREE.Vector4(x * dpr, y * dpr, width * dpr, height * dpr):WebGLRendererではArrayCameraのビューポートは描画バッファーのピクセル単位です(WebGPURendererではCSSピクセルをピクセル比で拡大します)。そのため、分数を指定すると何も描画されません。
  • cubeCamera.update(renderer, scene) → mesh.visible = false; cubeCamera.update(renderer, scene); mesh.visible = true;:表示中の反射メッシュは、そのマテリアルがサンプリングするキューブマップ自体に描画されます。
  • scene.background = texture → texture.mapping = THREE.EquirectangularReflectionMapping; scene.background = texture:正距円筒図法またはキューブマッピングを指定しないと、テクスチャはスカイボックスではなく、画面全体を覆う平面として描画されます。
  • import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js" → import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js":標準のインポートマップではthree/examples/jsm/指定子を解決できません。代わりにthree/addons/がマッピングされています。
  • <script src="three.min.js"></script> → <script type="module">import * as THREE from "three";</script>:r161でbuild/three.jsとbuild/three.min.jsが削除されたため、ブラウザーではインポートマップを介したESモジュールとしてthree.jsを読み込みます。
  • mesh.layers.set(1) → mesh.layers.enable(1):setはレイヤーマスクを置き換えるため、デフォルトのカメラとライトがあるレイヤー0からメッシュが外れます。
  • renderer.outputEncoding = THREE.sRGBEncoding → renderer.outputColorSpace = THREE.SRGBColorSpace:エンコーディングAPIはなくなりました。また、色空間プロパティはすでにデフォルトでSRGBColorSpaceなので、通常はこの代入は不要です。
  • renderer.physicallyCorrectLights = true → const bulb = new THREE.PointLight(0xffffff, 100):物理ベースのライト単位は常に有効で、physicallyCorrectLightsとuseLegacyLightsの切り替え設定はなくなりました。そのため、この行を削除し、距離に応じたカンデラ値をポイントライトとスポットライトに設定してください(threejs-lighting)。
  • material.envMapIntensity = 0.5 → scene.environmentIntensity = 0.5:envMapIntensityが強度を調整するのはマテリアル独自のenvMapのみで、scene.environmentには適用されません。
  • mesh.dispose() → mesh.dispose(); mesh.geometry.dispose(); for (const value of Object.values(mesh.material)) if (value?.isTexture) value.dispose(); mesh.material.dispose();:オブジェクトレベルのdisposeで解放されるのはオブジェクトごとのレンダラー状態のみで、ジオメトリ、マテリアル、テクスチャは解放されません。また、material.dispose()でもテクスチャは解放されません。
  • import { WebGLCubeRenderTarget } from "three/webgpu" → import { CubeRenderTarget } from "three/webgpu":three/webgpuはWebGLCubeRenderTargetをエクスポートしておらず、WebGPURendererでは動作しません。WebGLRendererではそのまま使用してください。
  • await renderer.renderAsync(scene, camera) → await renderer.init(); renderer.render(scene, camera):非同期のレンダリングメソッドはr181で非推奨になりました。一度初期化した後は、ループ内で同期的にレンダリングしてください。

参考情報

  • threejs-geometry — BufferGeometry の作成と編集、インスタンシング、マージ、バウンディングボリューム。
  • threejs-materials — マテリアルとそのテクスチャスロットの選択と設定。
  • threejs-textures — テクスチャの読み込み、色空間、UV チャンネル。
  • threejs-lighting — ライトの種類、単位、シャドウの設定。
  • threejs-animation — キーフレームアニメーションのための AnimationMixer とクリップシステム。
  • threejs-interaction — レイキャスト、ポインターイベント、カメラコントロール。
  • threejs-loaders — glTF などのファイルローダー、非同期読み込みのパターン。
  • threejs-shaders — WebGLRenderer での ShaderMaterial と GLSL、WebGPURenderer での TSL ノードマテリアル。
  • threejs-postprocessing — EffectComposer のパスと WebGPU レンダーパイプライン。
  • threejs-performance — フレームコストの測定と、ドローコール、メモリ、フィルレートの削減。
  • threejs-react-three-fiber — 同じシーングラフを React コンポーネントとして記述します。

コメント