Reorganize: Move all skills to skills/ folder
- Created skills/ directory - Moved 272 skills to skills/ subfolder - Kept agents/ at root level - Kept installation scripts and docs at root level Repository structure: - skills/ - All 272 skills from skills.sh - agents/ - Agent definitions - *.sh, *.ps1 - Installation scripts - README.md, etc. - Documentation Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
481
skills/threejs-lighting/skill.md
Normal file
481
skills/threejs-lighting/skill.md
Normal file
@@ -0,0 +1,481 @@
|
||||
---
|
||||
name: threejs-lighting
|
||||
description: Three.js lighting - light types, shadows, environment lighting. Use when adding lights, configuring shadows, setting up IBL, or optimizing lighting performance.
|
||||
---
|
||||
|
||||
# Three.js Lighting
|
||||
|
||||
## Quick Start
|
||||
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
|
||||
// Basic lighting setup
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
|
||||
directionalLight.position.set(5, 5, 5);
|
||||
scene.add(directionalLight);
|
||||
```
|
||||
|
||||
## Light Types Overview
|
||||
|
||||
| Light | Description | Shadow Support | Cost |
|
||||
| ---------------- | ---------------------- | -------------- | -------- |
|
||||
| AmbientLight | Uniform everywhere | No | Very Low |
|
||||
| HemisphereLight | Sky/ground gradient | No | Very Low |
|
||||
| DirectionalLight | Parallel rays (sun) | Yes | Low |
|
||||
| PointLight | Omnidirectional (bulb) | Yes | Medium |
|
||||
| SpotLight | Cone-shaped | Yes | Medium |
|
||||
| RectAreaLight | Area light (window) | No\* | High |
|
||||
|
||||
\*RectAreaLight shadows require custom solutions
|
||||
|
||||
## AmbientLight
|
||||
|
||||
Illuminates all objects equally. No direction, no shadows.
|
||||
|
||||
```javascript
|
||||
// AmbientLight(color, intensity)
|
||||
const ambient = new THREE.AmbientLight(0xffffff, 0.5);
|
||||
scene.add(ambient);
|
||||
|
||||
// Modify at runtime
|
||||
ambient.color.set(0xffffcc);
|
||||
ambient.intensity = 0.3;
|
||||
```
|
||||
|
||||
## HemisphereLight
|
||||
|
||||
Gradient from sky to ground color. Good for outdoor scenes.
|
||||
|
||||
```javascript
|
||||
// HemisphereLight(skyColor, groundColor, intensity)
|
||||
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b4513, 0.6);
|
||||
hemi.position.set(0, 50, 0);
|
||||
scene.add(hemi);
|
||||
|
||||
// Properties
|
||||
hemi.color; // Sky color
|
||||
hemi.groundColor; // Ground color
|
||||
hemi.intensity;
|
||||
```
|
||||
|
||||
## DirectionalLight
|
||||
|
||||
Parallel light rays. Simulates distant light source (sun).
|
||||
|
||||
```javascript
|
||||
// DirectionalLight(color, intensity)
|
||||
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
|
||||
dirLight.position.set(5, 10, 5);
|
||||
|
||||
// Light points at target (default: 0, 0, 0)
|
||||
dirLight.target.position.set(0, 0, 0);
|
||||
scene.add(dirLight.target);
|
||||
|
||||
scene.add(dirLight);
|
||||
```
|
||||
|
||||
### DirectionalLight Shadows
|
||||
|
||||
```javascript
|
||||
dirLight.castShadow = true;
|
||||
|
||||
// Shadow map size (higher = sharper, more expensive)
|
||||
dirLight.shadow.mapSize.width = 2048;
|
||||
dirLight.shadow.mapSize.height = 2048;
|
||||
|
||||
// Shadow camera (orthographic)
|
||||
dirLight.shadow.camera.near = 0.5;
|
||||
dirLight.shadow.camera.far = 50;
|
||||
dirLight.shadow.camera.left = -10;
|
||||
dirLight.shadow.camera.right = 10;
|
||||
dirLight.shadow.camera.top = 10;
|
||||
dirLight.shadow.camera.bottom = -10;
|
||||
|
||||
// Shadow softness
|
||||
dirLight.shadow.radius = 4; // Blur radius (PCFSoftShadowMap only)
|
||||
|
||||
// Shadow bias (fixes shadow acne)
|
||||
dirLight.shadow.bias = -0.0001;
|
||||
dirLight.shadow.normalBias = 0.02;
|
||||
|
||||
// Helper to visualize shadow camera
|
||||
const helper = new THREE.CameraHelper(dirLight.shadow.camera);
|
||||
scene.add(helper);
|
||||
```
|
||||
|
||||
## PointLight
|
||||
|
||||
Emits light in all directions from a point. Like a light bulb.
|
||||
|
||||
```javascript
|
||||
// PointLight(color, intensity, distance, decay)
|
||||
const pointLight = new THREE.PointLight(0xffffff, 1, 100, 2);
|
||||
pointLight.position.set(0, 5, 0);
|
||||
scene.add(pointLight);
|
||||
|
||||
// Properties
|
||||
pointLight.distance; // Maximum range (0 = infinite)
|
||||
pointLight.decay; // Light falloff (physically correct = 2)
|
||||
```
|
||||
|
||||
### PointLight Shadows
|
||||
|
||||
```javascript
|
||||
pointLight.castShadow = true;
|
||||
pointLight.shadow.mapSize.width = 1024;
|
||||
pointLight.shadow.mapSize.height = 1024;
|
||||
|
||||
// Shadow camera (perspective - 6 directions for cube map)
|
||||
pointLight.shadow.camera.near = 0.5;
|
||||
pointLight.shadow.camera.far = 50;
|
||||
|
||||
pointLight.shadow.bias = -0.005;
|
||||
```
|
||||
|
||||
## SpotLight
|
||||
|
||||
Cone-shaped light. Like a flashlight or stage light.
|
||||
|
||||
```javascript
|
||||
// SpotLight(color, intensity, distance, angle, penumbra, decay)
|
||||
const spotLight = new THREE.SpotLight(0xffffff, 1, 100, Math.PI / 6, 0.5, 2);
|
||||
spotLight.position.set(0, 10, 0);
|
||||
|
||||
// Target (light points at this)
|
||||
spotLight.target.position.set(0, 0, 0);
|
||||
scene.add(spotLight.target);
|
||||
|
||||
scene.add(spotLight);
|
||||
|
||||
// Properties
|
||||
spotLight.angle; // Cone angle (radians, max Math.PI/2)
|
||||
spotLight.penumbra; // Soft edge (0-1)
|
||||
spotLight.distance; // Range
|
||||
spotLight.decay; // Falloff
|
||||
```
|
||||
|
||||
### SpotLight Shadows
|
||||
|
||||
```javascript
|
||||
spotLight.castShadow = true;
|
||||
spotLight.shadow.mapSize.width = 1024;
|
||||
spotLight.shadow.mapSize.height = 1024;
|
||||
|
||||
// Shadow camera (perspective)
|
||||
spotLight.shadow.camera.near = 0.5;
|
||||
spotLight.shadow.camera.far = 50;
|
||||
spotLight.shadow.camera.fov = 30;
|
||||
|
||||
spotLight.shadow.bias = -0.0001;
|
||||
|
||||
// Focus (affects shadow projection)
|
||||
spotLight.shadow.focus = 1;
|
||||
```
|
||||
|
||||
## RectAreaLight
|
||||
|
||||
Rectangular area light. Great for soft, realistic lighting.
|
||||
|
||||
```javascript
|
||||
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";
|
||||
import { RectAreaLightUniformsLib } from "three/examples/jsm/lights/RectAreaLightUniformsLib.js";
|
||||
|
||||
// Must initialize uniforms first
|
||||
RectAreaLightUniformsLib.init();
|
||||
|
||||
// RectAreaLight(color, intensity, width, height)
|
||||
const rectLight = new THREE.RectAreaLight(0xffffff, 5, 4, 2);
|
||||
rectLight.position.set(0, 5, 0);
|
||||
rectLight.lookAt(0, 0, 0);
|
||||
scene.add(rectLight);
|
||||
|
||||
// Helper
|
||||
const helper = new RectAreaLightHelper(rectLight);
|
||||
rectLight.add(helper);
|
||||
|
||||
// Note: Only works with MeshStandardMaterial and MeshPhysicalMaterial
|
||||
// Does not cast shadows natively
|
||||
```
|
||||
|
||||
## Shadow Setup
|
||||
|
||||
### Enable Shadows
|
||||
|
||||
```javascript
|
||||
// 1. Enable on renderer
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
|
||||
// Shadow map types:
|
||||
// THREE.BasicShadowMap - fastest, low quality
|
||||
// THREE.PCFShadowMap - default, filtered
|
||||
// THREE.PCFSoftShadowMap - softer edges
|
||||
// THREE.VSMShadowMap - variance shadow map
|
||||
|
||||
// 2. Enable on light
|
||||
light.castShadow = true;
|
||||
|
||||
// 3. Enable on objects
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
// Ground plane
|
||||
floor.receiveShadow = true;
|
||||
floor.castShadow = false; // Usually false for floors
|
||||
```
|
||||
|
||||
### Optimizing Shadows
|
||||
|
||||
```javascript
|
||||
// Tight shadow camera frustum
|
||||
const d = 10;
|
||||
dirLight.shadow.camera.left = -d;
|
||||
dirLight.shadow.camera.right = d;
|
||||
dirLight.shadow.camera.top = d;
|
||||
dirLight.shadow.camera.bottom = -d;
|
||||
dirLight.shadow.camera.near = 0.5;
|
||||
dirLight.shadow.camera.far = 30;
|
||||
|
||||
// Fix shadow acne
|
||||
dirLight.shadow.bias = -0.0001; // Depth bias
|
||||
dirLight.shadow.normalBias = 0.02; // Bias along normal
|
||||
|
||||
// Shadow map size (balance quality vs performance)
|
||||
// 512 - low quality
|
||||
// 1024 - medium quality
|
||||
// 2048 - high quality
|
||||
// 4096 - very high quality (expensive)
|
||||
```
|
||||
|
||||
### Contact Shadows (Fake, Fast)
|
||||
|
||||
```javascript
|
||||
import { ContactShadows } from "three/examples/jsm/objects/ContactShadows.js";
|
||||
|
||||
const contactShadows = new ContactShadows({
|
||||
resolution: 512,
|
||||
blur: 2,
|
||||
opacity: 0.5,
|
||||
scale: 10,
|
||||
position: [0, 0, 0],
|
||||
});
|
||||
scene.add(contactShadows);
|
||||
```
|
||||
|
||||
## Light Helpers
|
||||
|
||||
```javascript
|
||||
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";
|
||||
|
||||
// DirectionalLight helper
|
||||
const dirHelper = new THREE.DirectionalLightHelper(dirLight, 5);
|
||||
scene.add(dirHelper);
|
||||
|
||||
// PointLight helper
|
||||
const pointHelper = new THREE.PointLightHelper(pointLight, 1);
|
||||
scene.add(pointHelper);
|
||||
|
||||
// SpotLight helper
|
||||
const spotHelper = new THREE.SpotLightHelper(spotLight);
|
||||
scene.add(spotHelper);
|
||||
|
||||
// Hemisphere helper
|
||||
const hemiHelper = new THREE.HemisphereLightHelper(hemiLight, 5);
|
||||
scene.add(hemiHelper);
|
||||
|
||||
// RectAreaLight helper
|
||||
const rectHelper = new RectAreaLightHelper(rectLight);
|
||||
rectLight.add(rectHelper);
|
||||
|
||||
// Update helpers when light changes
|
||||
dirHelper.update();
|
||||
spotHelper.update();
|
||||
```
|
||||
|
||||
## Environment Lighting (IBL)
|
||||
|
||||
Image-Based Lighting using HDR environment maps.
|
||||
|
||||
```javascript
|
||||
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
|
||||
|
||||
const rgbeLoader = new RGBELoader();
|
||||
rgbeLoader.load("environment.hdr", (texture) => {
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping;
|
||||
|
||||
// Set as scene environment (affects all PBR materials)
|
||||
scene.environment = texture;
|
||||
|
||||
// Optional: also use as background
|
||||
scene.background = texture;
|
||||
scene.backgroundBlurriness = 0; // 0-1, blur the background
|
||||
scene.backgroundIntensity = 1;
|
||||
});
|
||||
|
||||
// PMREMGenerator for better reflections
|
||||
const pmremGenerator = new THREE.PMREMGenerator(renderer);
|
||||
pmremGenerator.compileEquirectangularShader();
|
||||
|
||||
rgbeLoader.load("environment.hdr", (texture) => {
|
||||
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
|
||||
scene.environment = envMap;
|
||||
texture.dispose();
|
||||
pmremGenerator.dispose();
|
||||
});
|
||||
```
|
||||
|
||||
### Cube Texture Environment
|
||||
|
||||
```javascript
|
||||
const cubeLoader = new THREE.CubeTextureLoader();
|
||||
const envMap = cubeLoader.load([
|
||||
"px.jpg",
|
||||
"nx.jpg",
|
||||
"py.jpg",
|
||||
"ny.jpg",
|
||||
"pz.jpg",
|
||||
"nz.jpg",
|
||||
]);
|
||||
|
||||
scene.environment = envMap;
|
||||
scene.background = envMap;
|
||||
```
|
||||
|
||||
## Light Probes (Advanced)
|
||||
|
||||
Capture lighting from a point in space for ambient lighting.
|
||||
|
||||
```javascript
|
||||
import { LightProbeGenerator } from "three/examples/jsm/lights/LightProbeGenerator.js";
|
||||
|
||||
// Generate from cube texture
|
||||
const lightProbe = new THREE.LightProbe();
|
||||
scene.add(lightProbe);
|
||||
|
||||
lightProbe.copy(LightProbeGenerator.fromCubeTexture(cubeTexture));
|
||||
|
||||
// Or from render target
|
||||
const cubeCamera = new THREE.CubeCamera(
|
||||
0.1,
|
||||
100,
|
||||
new THREE.WebGLCubeRenderTarget(256),
|
||||
);
|
||||
cubeCamera.update(renderer, scene);
|
||||
lightProbe.copy(
|
||||
LightProbeGenerator.fromCubeRenderTarget(renderer, cubeCamera.renderTarget),
|
||||
);
|
||||
```
|
||||
|
||||
## Common Lighting Setups
|
||||
|
||||
### Three-Point Lighting
|
||||
|
||||
```javascript
|
||||
// Key light (main light)
|
||||
const keyLight = new THREE.DirectionalLight(0xffffff, 1);
|
||||
keyLight.position.set(5, 5, 5);
|
||||
scene.add(keyLight);
|
||||
|
||||
// Fill light (softer, opposite side)
|
||||
const fillLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
||||
fillLight.position.set(-5, 3, 5);
|
||||
scene.add(fillLight);
|
||||
|
||||
// Back light (rim lighting)
|
||||
const backLight = new THREE.DirectionalLight(0xffffff, 0.3);
|
||||
backLight.position.set(0, 5, -5);
|
||||
scene.add(backLight);
|
||||
|
||||
// Ambient fill
|
||||
const ambient = new THREE.AmbientLight(0x404040, 0.3);
|
||||
scene.add(ambient);
|
||||
```
|
||||
|
||||
### Outdoor Daylight
|
||||
|
||||
```javascript
|
||||
// Sun
|
||||
const sun = new THREE.DirectionalLight(0xffffcc, 1.5);
|
||||
sun.position.set(50, 100, 50);
|
||||
sun.castShadow = true;
|
||||
scene.add(sun);
|
||||
|
||||
// Sky ambient
|
||||
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b4513, 0.6);
|
||||
scene.add(hemi);
|
||||
```
|
||||
|
||||
### Indoor Studio
|
||||
|
||||
```javascript
|
||||
// Multiple area lights
|
||||
RectAreaLightUniformsLib.init();
|
||||
|
||||
const light1 = new THREE.RectAreaLight(0xffffff, 5, 2, 2);
|
||||
light1.position.set(3, 3, 3);
|
||||
light1.lookAt(0, 0, 0);
|
||||
scene.add(light1);
|
||||
|
||||
const light2 = new THREE.RectAreaLight(0xffffff, 3, 2, 2);
|
||||
light2.position.set(-3, 3, 3);
|
||||
light2.lookAt(0, 0, 0);
|
||||
scene.add(light2);
|
||||
|
||||
// Ambient fill
|
||||
const ambient = new THREE.AmbientLight(0x404040, 0.2);
|
||||
scene.add(ambient);
|
||||
```
|
||||
|
||||
## Light Animation
|
||||
|
||||
```javascript
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
function animate() {
|
||||
const time = clock.getElapsedTime();
|
||||
|
||||
// Orbit light around scene
|
||||
light.position.x = Math.cos(time) * 5;
|
||||
light.position.z = Math.sin(time) * 5;
|
||||
|
||||
// Pulsing intensity
|
||||
light.intensity = 1 + Math.sin(time * 2) * 0.5;
|
||||
|
||||
// Color cycling
|
||||
light.color.setHSL((time * 0.1) % 1, 1, 0.5);
|
||||
|
||||
// Update helpers if using
|
||||
lightHelper.update();
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Limit light count**: Each light adds shader complexity
|
||||
2. **Use baked lighting**: For static scenes, bake to textures
|
||||
3. **Smaller shadow maps**: 512-1024 often sufficient
|
||||
4. **Tight shadow frustums**: Only cover needed area
|
||||
5. **Disable unused shadows**: Not all lights need shadows
|
||||
6. **Use light layers**: Exclude objects from certain lights
|
||||
|
||||
```javascript
|
||||
// Light layers
|
||||
light.layers.set(1); // Light only affects layer 1
|
||||
mesh.layers.enable(1); // Mesh is on layer 1
|
||||
otherMesh.layers.disable(1); // Other mesh not affected
|
||||
|
||||
// Selective shadows
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
decorMesh.castShadow = false; // Small objects often don't need to cast
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-materials` - Material light response
|
||||
- `threejs-textures` - Lightmaps and environment maps
|
||||
- `threejs-postprocessing` - Bloom and other light effects
|
||||
Reference in New Issue
Block a user