init
This commit is contained in:
298
.opencode/skills/threejs/references/13-node-materials.md
Normal file
298
.opencode/skills/threejs/references/13-node-materials.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user