mcpField
T
threejs-lighting

threejs-lighting

github.com/cloudai-xクリエイティブ・メディア3.8k14.0k 回インストール1 週間前に更新
リポジトリ

threejs-lighting について

Three.js 開発者向けのライティング解説スキルです。各種ライト、シャドウ、環境光を扱い、WebGLRenderer と WebGPURenderer の例を示します。

主な機能

  1. 01ライトの種類と単位の解説
  2. 02シャドウの設定とデバッグ
  3. 03環境光とライトプローブの設定
  4. 04照明構成とアニメーション例

活用シーン

  1. 01シーンに適したライトの選択
  2. 02各ライトのシャドウ調整
  3. 03マテリアルへの HDR 環境光の追加

インストール

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

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

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

詳細

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();

const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(4, 3, 8);

// A single directional light: intensity is a plain multiplier, no distance falloff
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5);
scene.add(dirLight);

const floor = new THREE.Mesh(
  new THREE.PlaneGeometry(20, 20),
  new THREE.MeshStandardMaterial({ color: 0x808080 })
);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);

const mesh = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshStandardMaterial({ color: 0x3a76c4 })
);
scene.add(mesh);

// Shadows need three switches: renderer, light, and the meshes that cast and receive
renderer.shadowMap.enabled = true;
dirLight.castShadow = true;
mesh.castShadow = true;
floor.receiveShadow = true;

function animate() {
  renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);

ライトの種類と単位

ライト影光度備考
AmbientLightなし乗数あらゆる方向からの均一な照明
HemisphereLightなし乗数上方からは空の色、下方からは地面の色
DirectionalLightあり乗数平行光線(太陽)。ターゲットを照らします
SunLight (addon)あり、カスケード乗数ビューに合わせてシャドウフラスタムを自動調整します
PointLightあり、6 面カンデラ距離の二乗に反比例して減衰します(decay 2)
SpotLightありカンデラ円錐状に照射し、距離の二乗に反比例して減衰します(decay 2)
RectAreaLightなしニトMeshStandardMaterial と MeshPhysicalMaterial のみ
LightProbeなし乗数球面調和関数による環境光。通常はベイクして使用します

PointLight と SpotLight の光度はカンデラで、距離の二乗に反比例して減衰します(decay のデフォルトは 2)。1 カンデラのライトは 5 単位離れると 1/25 の光を与えるため、適切な値は距離によって異なり、通常は数百になります(公式ドキュメントの例では 80〜1000 を使用しています)。light.power は同じ値をルーメンで設定します。light.distance は滑らかな減衰範囲で、0 は制限なしを意味します。DirectionalLight、AmbientLight、HemisphereLight の光度は単位のない乗数です。RectAreaLight の光度はニト(平方メートルあたりのカンデラ)です。

AmbientLight と HemisphereLight

// AmbientLight(color, intensity) — a flat multiplier on every lit material
const ambient = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambient);

// HemisphereLight(skyColor, groundColor, intensity)
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b6f47, 0.6);
scene.add(hemi);

DirectionalLight

// DirectionalLight(color, intensity): parallel rays from position towards target; the distance only matters to the shadow camera
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5);

// Shines from its position towards target; add the target to the scene when you move it
dirLight.target.position.set(0, 0, 0);
scene.add(dirLight.target);
scene.add(dirLight);
SunLight:カスケードシャドウの自動調整

SunLight(three/addons/lights/SunLight.js)は、大規模なシーンに適した、シャドウマップを 2 つ持つ平行光源です。ターゲットはなく、位置から原点に向けて照射します。デフォルトでは真下に向けて照射します。WebGLRenderer ではそのまま動作します。WebGPURenderer では、先に登録してください(WebGPU と TSL を参照)。

import { SunLight } from "three/addons/lights/SunLight.js";

const sun = new SunLight(0xfff2e3, 3);
sun.position.set(100, 160, 60);
sun.castShadow = true;
scene.add(sun);

カスケードはカメラのビューフラスタムを分割した範囲に自動的に合わせられます。範囲は sun.shadow.camera.far とビューカメラの far 面のうち、近い方までです。shadow.camera.left/right/top/bottom は無視されます。デフォルトの mapSize は、カスケードごとに 1024 × 1024 です。手動で調整するシャドウフラスタムはありません。

PointLight と SpotLight

// PointLight(color, intensity in candela, distance, decay)
const bulb = new THREE.PointLight(0xffdcb0, 100, 20, 2);
bulb.position.set(0, 4, 0);
scene.add(bulb);

// SpotLight(color, intensity in candela, distance, angle, penumbra, decay)
const deskLamp = new THREE.SpotLight(0xffffff, 250, 30, Math.PI / 6, 0.4, 2);
deskLamp.position.set(2, 5, 0);
deskLamp.target.position.set(0, 0, 0);
scene.add(deskLamp.target);
scene.add(deskLamp);

// Prefer lumens: power writes the candela intensity for you
bulb.power = 800;

angle は円錐の半角(ラジアン)で、上限は Math.PI / 2 です。penumbra(0〜1)を指定すると、円錐の縁がぼやけます。

RectAreaLight

窓や帯状のライトのような柔らかな照明を作る矩形の光源です。MeshStandardMaterial と MeshPhysicalMaterial のみを照らし、影は生成できません。

import { RectAreaLightHelper } from "three/addons/helpers/RectAreaLightHelper.js";
import { RectAreaLightUniformsLib } from "three/addons/lights/RectAreaLightUniformsLib.js";

// WebGLRenderer: add the LTC lookup textures to the renderer's uniforms, once
RectAreaLightUniformsLib.init();

// RectAreaLight(color, intensity in nits, width, height)
const windowLight = new THREE.RectAreaLight(0xffffff, 5, 4, 10);
windowLight.position.set(-5, 5, 0);
windowLight.lookAt(0, 0, 0); // emits from its front face
scene.add(windowLight);

// The helper must be added as a child of the light
const helper = new RectAreaLightHelper(windowLight);
windowLight.add(helper);

WebGPURenderer では、代わりに RectAreaLightTexturesLib を使って LTC テクスチャを登録してください(WebGPU と TSL を参照)。

影

// 1. Renderer: shadow maps are off by default; PCFShadowMap is the soft filtered default,
// VSMShadowMap blurs the map itself, BasicShadowMap is hard-edged
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;

// 2. Light
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5);
dirLight.castShadow = true;
scene.add(dirLight);

// 3. Objects
mesh.castShadow = true;
mesh.receiveShadow = true;

shadow.radius を 1 より大きくすると、PCF フィルターと VSM のぼかし範囲が広がります。BasicShadowMap では効果がありません。VSM では shadow.blurSamples(デフォルトは 8)も設定できます。PointLight の影は VSM に対応していません。WebGLRenderer は警告を出して、そのライトの影をスキップします。PCFSoftShadowMap は非推奨です。警告が出て、すでにソフトな PCFShadowMap にフォールバックします。VSMShadowMap を使用すると、影を受けるすべてのメッシュが影も生成します。

DirectionalLight の影の調整
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5); // every caster must lie between near and far from here
dirLight.castShadow = true;

// The shadow camera sits at the light's position and looks at its target: near and far
// are distances from the light; left/right/top/bottom frame the area around the target
const shadowCam = dirLight.shadow.camera;
shadowCam.left = -10;
shadowCam.right = 10;
shadowCam.top = 10;
shadowCam.bottom = -10;
shadowCam.near = 0.5;
shadowCam.far = 50;
shadowCam.updateProjectionMatrix(); // needed whenever these change after the first render

dirLight.shadow.mapSize.set(2048, 2048); // powers of two

// Acne: normalBias offsets the lookup along the surface normal (light grazing a surface);
// bias offsets the depth compared against the map — start tiny, negative fights acne
dirLight.shadow.normalBias = 0.02;
dirLight.shadow.bias = -0.0001;

// Lighten shadows without adding fill lights: 0 removes, 1 is full darkness
dirLight.shadow.intensity = 0.7;
PointLight と SpotLight のシャドウカメラは自動的に設定されます

レンダラーは、シャドウを描画するたびにこれらのカメラを再構築します。スポットライトのシャドウの fov は 2 × angle × shadow.focus(度数法)で、far は light.distance から設定されます。ポイントライトの far も light.distance から設定されます。fov は常に上書きされ、手動で設定した far が維持されるのは distance が 0 の場合のみです。angle と shadow.focus で円錐を、distance で照射範囲を調整してください。

const deskLamp = new THREE.SpotLight(0xffffff, 250, 30);
deskLamp.castShadow = true;
deskLamp.shadow.mapSize.set(1024, 1024);
deskLamp.shadow.focus = 0.9; // shadow fov as a fraction of the light's cone
deskLamp.shadow.bias = -0.0001;

DirectionalLight または SpotLight のシャドウカメラを可視化するには、new THREE.CameraHelper(light.shadow.camera) をシーンに追加し、カメラを変更した後にヘルパーの update() を呼び出してください。

コンタクトシャドウ(フェイク、低コスト)

接地感を出すためにライトごとにシャドウマップを用意するのは過剰です。放射状グラデーションのブロブなら、テクスチャ付きの四角形1枚で済みます。

// A soft blob under the object: no shadow map, works under both renderers
const size = 128;
const canvas = document.createElement("canvas");
canvas.width = canvas.height = size;
const ctx = canvas.getContext("2d");
const gradient = ctx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);
gradient.addColorStop(0, "rgba(0,0,0,0.6)");
gradient.addColorStop(1, "rgba(0,0,0,0)");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, size, size);

const shadowTexture = new THREE.CanvasTexture(canvas);
shadowTexture.colorSpace = THREE.SRGBColorSpace; // a canvas used as a color map is sRGB

const blob = new THREE.Mesh(
  new THREE.PlaneGeometry(2, 2),
  new THREE.MeshBasicMaterial({ map: shadowTexture, transparent: true, depthWrite: false })
);
blob.rotation.x = -Math.PI / 2;
blob.position.y = 0.001; // just above the floor to avoid z-fighting
scene.add(blob);

オブジェクトのシルエットに沿うブロブを作るには、下から深度をレンダーターゲットに描画してぼかします。公式の webgl_shadow_contact の例では、three/addons/shaders/ の HorizontalBlurShader と VerticalBlurShader を使っています。

ライトヘルパー

const dirLight = new THREE.DirectionalLight(0xffffff, 3);
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b6f47, 0.6);
const bulb = new THREE.PointLight(0xffdcb0, 100, 20);
const deskLamp = new THREE.SpotLight(0xffffff, 250, 30);
scene.add(dirLight, hemi, bulb, deskLamp);

// Built-in helpers are objects: add them to the scene
const dirHelper = new THREE.DirectionalLightHelper(dirLight, 5);
const pointHelper = new THREE.PointLightHelper(bulb, 0.5);
const spotHelper = new THREE.SpotLightHelper(deskLamp);
const hemiHelper = new THREE.HemisphereLightHelper(hemi, 5);
scene.add(dirHelper, pointHelper, spotHelper, hemiHelper);

すべてのライトヘルパーは、update() のときだけライトの色をコピーします。また、DirectionalLightHelper、SpotLightHelper、HemisphereLightHelper もそのときだけ向きを再設定します。ライトの色を変更した後、およびこの3種類のライトを移動または再び向け直した後は、update() を呼び出してください。

環境ライティング(IBL)

import { HDRLoader } from "three/addons/loaders/HDRLoader.js";

// Both renderers prefilter an equirect environment themselves: assign it directly
const hdr = await new HDRLoader().loadAsync("sunset.hdr");
hdr.mapping = THREE.EquirectangularReflectionMapping;

scene.environment = hdr; // lights the scene
scene.background = hdr; // optional: also draw it behind the scene
scene.environmentIntensity = 1; // scales the lighting contribution only
scene.environmentRotation.set(0, Math.PI / 4, 0); // rotates the lighting
scene.backgroundBlurriness = 0; // blurs the background, not the lighting
scene.backgroundIntensity = 1;
scene.backgroundRotation.set(0, 0, 0); // rotates the background independently

どちらのレンダラーも scene.environment によって MeshStandardMaterial と MeshPhysicalMaterial を照らします。WebGLRenderer は MeshLambertMaterial と MeshPhongMaterial も照らしますが、WebGPURenderer は照らしません。シーンから生成した環境には PMREMGenerator を使い続けてください。equirect ファイルに対して使うと、レンダラーがすでに行っている事前フィルタリングを繰り返すだけです。

import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";

const pmrem = new THREE.PMREMGenerator(renderer);
const room = new RoomEnvironment();
scene.environment = pmrem.fromScene(room, 0.04).texture;
room.dispose(); // frees the room's geometries and materials
pmrem.dispose();

キューブテクスチャは、マッピングの指定なしで環境として使えます。

const cubeEnv = await new THREE.CubeTextureLoader().loadAsync([
  "px.jpg",
  "nx.jpg",
  "py.jpg",
  "ny.jpg",
  "pz.jpg",
  "nz.jpg",
]);

scene.environment = cubeEnv;
scene.background = cubeEnv;

ライトプローブ

import { LightProbeGenerator } from "three/addons/lights/LightProbeGenerator.js";

// Bake ambient spherical harmonics from what a cube camera sees
const cubeCamera = new THREE.CubeCamera(0.1, 100, new THREE.WebGLCubeRenderTarget(256));
cubeCamera.update(renderer, scene);

const lightProbe = await LightProbeGenerator.fromCubeRenderTarget(renderer, cubeCamera.renderTarget);
scene.add(lightProbe);

LightProbeGenerator.fromCubeTexture(cubeTexture) は、読み込み済みのキューブテクスチャから同期的にライトプローブを生成します。位置に応じて変化するアンビエントライティングには、代わりに3Dグリッドをベイクします。WebGLRenderer では LightProbeGridWebGL、WebGPURenderer では three/addons/lighting/ の LightProbeGrid を使います。WebGPURenderer では、three/webgpu の CubeRenderTarget でキューブのレンダーターゲットを作成してください。

import { LightProbeGridWebGL } from "three/addons/lighting/LightProbeGridWebGL.js";

// A 10 × 4 × 10 volume centered on its position, size + 1 probes per axis by default
const probeGrid = new LightProbeGridWebGL(10, 4, 10);
probeGrid.position.set(0, 2, 0);
scene.add(probeGrid);
probeGrid.bake(renderer, scene); // bake again when the static lighting changes

よくあるセットアップ

// Three-point lighting: key, fill, rim
const keyLight = new THREE.DirectionalLight(0xffffff, 2);
keyLight.position.set(5, 6, 4);

const fillLight = new THREE.DirectionalLight(0xffffff, 0.5);
fillLight.position.set(-5, 3, 5);

const backLight = new THREE.DirectionalLight(0xffffff, 1);
backLight.position.set(-4, 5, -6);

scene.add(keyLight, fillLight, backLight);
import { SunLight } from "three/addons/lights/SunLight.js";

// Outdoor daylight: sun with cascaded shadows plus a sky gradient
const sun = new SunLight(0xfff2e3, 3);
sun.position.set(100, 160, 60);
sun.castShadow = true;

const sky = new THREE.HemisphereLight(0x87ceeb, 0x8b6f47, 0.5);

scene.add(sun, sky);

ライトのアニメーション

// Timer drives per-frame time: update() first, then read it
const timer = new THREE.Timer();
timer.connect(document); // avoids huge deltas after tab switches

const lamp = new THREE.PointLight(0xffd0a0, 100, 20);
scene.add(lamp);

function animate() {
  timer.update();

  const t = timer.getElapsed();
  lamp.position.set(Math.cos(t) * 4, 3, Math.sin(t) * 4);
  lamp.intensity = 100 + Math.sin(t * 2) * 30;

  renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);

パフォーマンス

  • どちらのレンダラーも、ライトの構成をすべてのライティング対応マテリアルにコンパイルします。ライトの追加・削除(WebGPURenderer では AmbientLight のみ)、または castShadow の切り替えによって、マテリアルが再コンパイルされます。使わないライトは削除し、実行時にライトをオン・オフするには intensity を使ってください。WebGPURenderer では、影を落とすライトがなく、スポットライトに map が設定されていない限り、DynamicLighting によってアンビエントライト、半球ライト、ディレクショナルライト、ポイントライト、スポットライトの増減時にもマテリアルのコンパイル状態を維持できます。また、ClusteredLighting は多数のポイントライトに対応できるよう拡張できます(WebGPU と TSL を参照)。
  • 影を落とすライトは、深度パスを追加します(ポイントライト1つにつき6パス)。影が不要な場所では castShadow をオフにしてください。
  • 静的なシーンでは、light.shadow.autoUpdate = false; light.shadow.needsUpdate = true; で必要なときにライトの影をレンダリングし、何かが移動した後にもう一度 light.shadow.needsUpdate = true; を設定します(どちらのレンダラーにも対応。WebGLRenderer にはグローバルな renderer.shadowMap.autoUpdate もあります)。
  • ディレクショナルライトのシャドウフラスタムは範囲を絞るか、ビューに合わせて自動調整される SunLight に切り替えてください。
  • ライトはメッシュごとにレイヤーでフィルタリングされません。ライトのレイヤーはカメラのレイヤーとの照合にのみ使われます。選択したメッシュだけを照らすには、WebGPURenderer で material.lightsNode を使ってください。

WebGPU と TSL

ライトクラス、シャドウ設定、および上記のシーンの環境プロパティは、WebGPURenderer にも引き継がれます。ただし、このセクションで置き換える WebGL 専用の項目は除きます。具体的には、RectAreaLightUniformsLib、WebGLCubeRenderTarget(CubeRenderTarget を使用)、LightProbeGridWebGL(LightProbeGrid を使用)、およびグローバルな renderer.shadowMap.autoUpdate です。SunLight は登録が必要です。また、ここでは scene.environment は Lambert マテリアルや Phong マテリアルを照らしません。

import * as THREE from "three/webgpu";

const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init(); // 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(0x101010); // the WebGPU canvas is transparent by default

const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(4, 3, 8);

renderer.shadowMap.enabled = true;
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.castShadow = true;
scene.add(dirLight);

function animate() {
  renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);
import * as THREE from "three/webgpu";
import { RectAreaLightTexturesLib } from "three/addons/lights/RectAreaLightTexturesLib.js";
import { SunLight } from "three/addons/lights/SunLight.js";
import { SunLightNode } from "three/addons/lights/SunLightNode.js";
import { ClusteredLighting } from "three/addons/lighting/ClusteredLighting.js";

// RectAreaLight: register the LTC textures once (replaces RectAreaLightUniformsLib)
THREE.RectAreaLightNode.setLTC(RectAreaLightTexturesLib.init());
// SunLight: register its node implementation once
renderer.library.addLight(SunLightNode, SunLight);
// Many point lights: clustered Forward+ shading (DynamicLighting instead avoids recompiles when unshadowed lights come and go)
renderer.lighting = new ClusteredLighting();
import * as THREE from "three/webgpu";
import { lights } from "three/tsl";

const keyLight = new THREE.PointLight(0x66aaff, 120, 20);
scene.add(keyLight);

// A material lit only by keyLight, ignoring every other light in the scene
const material = new THREE.MeshStandardNodeMaterial();
material.lightsNode = lights([keyLight]);

色付きの影:renderer.shadowMap.transmitted = true にすると、キャスターは material.castShadowNode(vec4)から、または map と colorNode のアルファ値から、シャドウマップに色とアルファを書き込みます。material.receivedShadowNode(影の値を受け取る Fn)は、受光側での影の適用方法を変更し、このフラグがなくても機能します。

よくある間違い

  • light.layers.set(1); → material.lightsNode = lights([keyLight, fillLight]);:ライトはレイヤーによってメッシュごとにフィルタリングされません。ライトのレイヤーはカメラのレイヤーと照合されるため、これを設定するとシーン全体でライトがオフになります。マテリアルごとに選択するには、WebGPURenderer の下、または WebGLNodesHandler アドオンを介した WebGLRenderer の下でノードマテリアルが必要です。
  • new THREE.PointLight(0xffffff, 1, 100); → new THREE.PointLight(0xffffff, 100, 20);:ポイントライトとスポットライトの強度は逆二乗減衰を伴うカンデラ単位なので、距離があると 1 ではほとんど寄与しません。一般的な値は数百に達します。
  • renderer.useLegacyLights = true; → const bulb = new THREE.PointLight(0xffffff, 100, 20);:従来のライト単位は廃止されており、useLegacyLights も physicallyCorrectLights も何もしません。そのため、ポイントライトとスポットライトの強度はカンデラ単位で調整してください。
  • renderer.shadowMap.type = THREE.PCFSoftShadowMap; → renderer.shadowMap.type = THREE.PCFShadowMap;:PCFSoftShadowMap は r182 で非推奨になりました。どちらのレンダラーも警告を出して PCFShadowMap にフォールバックしますが、PCFShadowMap はすでにソフトな影を生成します。
  • lightProbe.copy(LightProbeGenerator.fromCubeRenderTarget(renderer, rt)); → lightProbe.copy(await LightProbeGenerator.fromCubeRenderTarget(renderer, rt));:この呼び出しは非同期で Promise を返すため、copy() では読み取れません。
  • new ContactShadows({ opacity: 0.5 }); → new THREE.Mesh(new THREE.PlaneGeometry(2, 2), new THREE.MeshBasicMaterial({ transparent: true, map: blobTexture }));:three.js に ContactShadows クラスはありません(drei のコンポーネントです)。放射状グラデーションの平面でコンタクトシャドウを再現してください。
  • scene.environment = pmremGenerator.fromEquirectangular(texture).texture; → texture.mapping = THREE.EquirectangularReflectionMapping; scene.environment = texture;:レンダラーが正距円筒図法の環境マップを自らプリフィルタリングするため、手動での PMREM による品質向上はありません。fromScene には引き続き PMREMGenerator を使用してください。
  • scene.background = hdr; → hdr.mapping = THREE.EquirectangularReflectionMapping; scene.background = hdr;:HDRLoader は UV マッピングのテクスチャを返すため、この行がないと背景が画面空間の平面画像として描画されます。
  • import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"; → import { HDRLoader } from "three/addons/loaders/HDRLoader.js";:RGBELoader は r180 で HDRLoader に改名されました。また、インポートマップで解決するには、アドオンを three/addons/ からインポートする必要があります。
  • spotLight.shadow.camera.fov = 30; → spotLight.shadow.focus = 0.9;:シャドウカメラの fov は各パスで 2 × angle × focus(度単位)として再計算されるため、ライトの angle と focus を使って調整してください。
  • const lamp = new THREE.PointLight(0xffffff, 100, 20); lamp.shadow.camera.far = 50; → const lamp = new THREE.PointLight(0xffffff, 100, 50);:distance が 0 以外の場合、各シャドウパスでシャドウカメラの far が上書きされます。distance を使って影の範囲を設定してください。手動で設定した far が保持されるのは distance が 0 の場合だけです。
  • material.envMapIntensity = 0.5; → scene.environmentIntensity = 0.5;:envMapIntensity はマテリアル自身の envMap のみをスケーリングし、scene.environment は対象にしません。
  • const clock = new THREE.Clock(); → const timer = new THREE.Timer(); timer.connect(document);:Clock は r183 で非推奨になりました。getDelta() または getElapsed() の前に、各フレームで timer.update() を呼び出してください。
  • RectAreaLightUniformsLib.init(); → THREE.RectAreaLightNode.setLTC(RectAreaLightTexturesLib.init());:WebGPURenderer では uniforms lib は読み込まれず、テクスチャが登録されるまでライトのノードは null の LTC ライブラリを参照します。

関連項目

  • threejs-materials — マテリアルが光にどう反応するか(roughness、metalness、material.envMap)。
  • threejs-textures — 環境マップの読み込みとテクスチャの色空間の設定。
  • threejs-shaders — fresnel リムなどのカスタム GLSL エフェクト、onBeforeCompile によるライティング対応組み込みマテリアルの拡張、TSL のライティング対応ノードマテリアル。
  • threejs-postprocessing — ブルームなど、ライティングに関連するエフェクト。
  • threejs-fundamentals — 物理スケールのライトや HDR 環境に対応するレンダラーの設定、トーンマッピング、露出。

コメント