Files
english/.opencode/skills/threejs/references/13-node-materials.md
2026-04-12 01:06:31 +07:00

299 lines
6.7 KiB
Markdown

# Node Materials (TSL - Three Shading Language)
Modern node-based material system for creating custom shaders visually.
## What is TSL?
Three Shading Language (TSL) is a node-based system for creating materials and shaders:
- Functional approach to shader composition
- Type-safe node graph
- Unified GLSL/WGSL output (WebGL & WebGPU)
- No manual shader code required
## Basic Node Material
```javascript
import * as THREE from 'three/webgpu';
import { color, texture, normalMap, MeshStandardNodeMaterial } from 'three/nodes';
const material = new MeshStandardNodeMaterial();
// Set base color node
material.colorNode = color(0xff0000);
// Or use texture
material.colorNode = texture(colorTexture);
// Combine nodes
material.colorNode = texture(colorTexture).mul(color(0xffffff));
// Normal mapping
material.normalNode = normalMap(normalTexture);
```
## Node Types
### Input Nodes
```javascript
import {
attribute,
uniform,
texture,
cubeTexture,
instancedArray,
storage
} from 'three/nodes';
// Geometry attributes
const positionNode = attribute('position');
const normalNode = attribute('normal');
const uvNode = attribute('uv');
// Uniforms
const timeNode = uniform(0); // value
// Textures
const colorNode = texture(diffuseTexture);
const envNode = cubeTexture(cubeMapTexture);
// Instanced data
const instanceColorNode = instancedArray('instanceColor');
// Storage buffers (compute)
const storageNode = storage(buffer, 'vec4', count);
```
### Math Nodes
```javascript
import { add, sub, mul, div, pow, sin, cos, length, normalize } from 'three/nodes';
// Basic operations
const result = add(a, b); // a + b
const result = sub(a, b); // a - b
const result = mul(a, b); // a * b
const result = div(a, b); // a / b
// Trigonometry
const result = sin(angle);
const result = cos(angle);
// Vector operations
const result = length(vector);
const result = normalize(vector);
// Chaining
const result = mul(texture(tex), color(0xff0000));
```
### Procedural Nodes
```javascript
import { checker, dots, noise, voronoi } from 'three/nodes';
// Checker pattern
material.colorNode = checker(uvNode.mul(10));
// Noise
material.colorNode = noise(uvNode.mul(5));
// Voronoi cells
material.colorNode = voronoi(uvNode.mul(3));
```
## Custom Shader Function
```javascript
import { Fn, vec3, float } from 'three/nodes';
// Define custom function
const customColor = Fn(([uv, time]) => {
const r = sin(uv.x.mul(10).add(time));
const g = cos(uv.y.mul(10).add(time));
const b = float(0.5);
return vec3(r, g, b);
});
// Use in material
material.colorNode = customColor(uvNode, timeNode);
```
## Animation with Nodes
```javascript
import { uniform, oscSine, timerLocal } from 'three/nodes';
// Oscillating value
const oscillator = oscSine(timerLocal(0.5)); // frequency = 0.5
// Pulsing color
material.colorNode = color(0xff0000).mul(oscillator.add(0.5));
// Rotating UV
const rotatedUV = uvNode.rotateUV(timerLocal());
material.colorNode = texture(tex, rotatedUV);
```
## Advanced Effects
### Fresnel Effect
```javascript
import { normalView, positionView, dot, pow } from 'three/nodes';
const fresnel = pow(
float(1).sub(dot(normalView, positionView.normalize())),
3
);
material.colorNode = mix(baseColor, edgeColor, fresnel);
```
### Vertex Displacement
```javascript
import { positionLocal, normalLocal, timerLocal, sin } from 'three/nodes';
// Displace vertices along normal
const displacement = sin(positionLocal.y.add(timerLocal())).mul(0.5);
material.positionNode = positionLocal.add(normalLocal.mul(displacement));
```
### Custom Normal Mapping
```javascript
import { normalMap, normalView, TBNViewMatrix } from 'three/nodes';
const normalMapNode = normalMap(normalTexture);
const transformedNormal = TBNViewMatrix.mul(normalMapNode);
material.normalNode = transformedNormal;
```
## Compute Shaders (WebGPU)
```javascript
import { compute, uniform, storage, Fn } from 'three/nodes';
// Define compute shader
const computeShader = Fn(() => {
const storageBuffer = storage(buffer, 'vec4', count);
const index = instanceIndex; // built-in
// Modify buffer
const value = storageBuffer.element(index);
storageBuffer.element(index).assign(value.mul(2));
})();
// Create compute node
const computeNode = compute(computeShader, 256); // workgroup size
// Execute
renderer.compute(computeNode);
```
## Node Material Types
```javascript
import {
MeshStandardNodeMaterial,
MeshPhysicalNodeMaterial,
MeshBasicNodeMaterial,
PointsNodeMaterial,
LineBasicNodeMaterial,
SpriteNodeMaterial
} from 'three/nodes';
// Standard PBR
const material = new MeshStandardNodeMaterial();
material.colorNode = colorNode;
material.roughnessNode = roughnessNode;
material.metalnessNode = metalnessNode;
// Physical (clearcoat, transmission, etc.)
const material = new MeshPhysicalNodeMaterial();
material.clearcoatNode = clearcoatNode;
material.transmissionNode = transmissionNode;
```
## Post-Processing with Nodes
```javascript
import { pass, PassNode } from 'three/nodes';
// Custom post-processing pass
const customPass = new PassNode('customPass', (input, output) => {
// input: previous pass texture
// output: render target
// Apply effect
const modifiedColor = input.mul(color(1, 0.5, 0.5));
output.assign(modifiedColor);
});
// Add to post-processing chain
postProcessing.addPass(customPass);
```
## Practical Example: Animated Material
```javascript
import * as THREE from 'three/webgpu';
import {
MeshStandardNodeMaterial,
texture,
uniform,
timerLocal,
sin,
cos,
vec2
} from 'three/nodes';
const material = new MeshStandardNodeMaterial();
// Animated UV scroll
const time = timerLocal();
const scrollSpeed = uniform(0.1);
const uvOffset = vec2(
time.mul(scrollSpeed),
sin(time).mul(0.1)
);
const scrolledUV = uv().add(uvOffset);
// Apply to color
material.colorNode = texture(diffuseTexture, scrolledUV);
// Animated emission
const pulseSpeed = uniform(2);
const emission = sin(time.mul(pulseSpeed)).mul(0.5).add(0.5);
material.emissiveNode = color(1, 0.5, 0).mul(emission);
```
## Migration from ShaderMaterial
```javascript
// Old way (ShaderMaterial)
const material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 }
},
vertexShader: `...`,
fragmentShader: `...`
});
// New way (Node Material)
const material = new MeshStandardNodeMaterial();
material.colorNode = customFunction(timerLocal());
// Much cleaner, type-safe, and reusable
```
## When to Use Node Materials
- Creating complex procedural materials
- Need both WebGL and WebGPU support
- Want visual/functional shader composition
- Reusable shader components
- Compute shader integration (WebGPU only)
**Note**: Node materials require WebGPU renderer for full features. Some features work with WebGL backend but compute shaders require WebGPU.