WebGL入门:Three.js高级材质与光照
大家好,我是欧阳瑞(Rich Own)。今天想和大家聊聊WebGL和Three.js的高级特性。作为一个全栈开发者和极客玩家,我对3D可视化有着浓厚的兴趣。今天就来分享一下Three.js中的高级材质和光照技术。
为什么选择Three.js?
Three.js是一个强大的3D图形库,封装了复杂的WebGL API,让我们可以轻松创建3D场景。
基础设置
javascript
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
高级材质
MeshStandardMaterial
javascript
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshStandardMaterial({
color: 0x00ffff,
metalness: 0.8,
roughness: 0.2,
envMap: environmentMap,
envMapIntensity: 1.0
});
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
MeshPhysicalMaterial
javascript
const material = new THREE.MeshPhysicalMaterial({
color: 0xff00ff,
metalness: 0.5,
roughness: 0.3,
clearcoat: 1.0,
clearcoatRoughness: 0.1,
transmission: 0.9,
ior: 1.5
});
ShaderMaterial
javascript
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
varying vec2 vUv;
void main() {
gl_FragColor = vec4(vUv.x, vUv.y, 0.5, 1.0);
}
`;
const material = new THREE.ShaderMaterial({
vertexShader,
fragmentShader
});
光照系统
AmbientLight
javascript
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
DirectionalLight
javascript
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
PointLight
javascript
const pointLight = new THREE.PointLight(0x00ffff, 1, 100);
pointLight.position.set(0, 5, 0);
pointLight.castShadow = true;
scene.add(pointLight);
SpotLight
javascript
const spotLight = new THREE.SpotLight(0xff00ff, 1);
spotLight.position.set(0, 10, 0);
spotLight.angle = Math.PI / 4;
spotLight.penumbra = 0.1;
spotLight.castShadow = true;
scene.add(spotLight);
RectAreaLight
javascript
const rectLight = new THREE.RectAreaLight(0x4e00ff, 10, 10, 10);
rectLight.position.set(0, 5, 0);
rectLight.lookAt(0, 0, 0);
scene.add(rectLight);
环境贴图
javascript
const loader = new THREE.CubeTextureLoader();
const environmentMap = loader.load([
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
]);
scene.background = environmentMap;
const material = new THREE.MeshStandardMaterial({
envMap: environmentMap,
metalness: 0.8,
roughness: 0.2
});
实战案例:赛博朋克场景
javascript
// 创建地面
const groundGeometry = new THREE.PlaneGeometry(50, 50);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x1a1a2e,
roughness: 0.8,
metalness: 0.2
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// 创建霓虹灯
function createNeonSign(text, position) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = 'bold 60px Arial';
ctx.fillStyle = '#00ffff';
ctx.shadowColor = '#00ffff';
ctx.shadowBlur = 50;
ctx.textAlign = 'center';
ctx.fillText(text, canvas.width / 2, canvas.height / 2 + 20);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
side: THREE.DoubleSide
});
const geometry = new THREE.PlaneGeometry(5, 1.2);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(position.x, position.y, position.z);
return mesh;
}
const sign1 = createNeonSign('CYBERPUNK', { x: 0, y: 3, z: 0 });
scene.add(sign1);
// 创建全息投影效果
function createHologram(position) {
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshPhongMaterial({
color: 0x00ffff,
transparent: true,
opacity: 0.3,
wireframe: true
});
const cube = new THREE.Mesh(geometry, material);
cube.position.set(position.x, position.y, position.z);
return cube;
}
const hologram = createHologram({ x: 5, y: 2, z: 5 });
scene.add(hologram);
// 添加动态效果
function update() {
sign1.rotation.y = Math.sin(Date.now() * 0.001) * 0.1;
hologram.rotation.x += 0.01;
hologram.rotation.y += 0.01;
}
后期处理
javascript
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // strength
0.4, // radius
0.85 // threshold
);
composer.addPass(bloomPass);
function animate() {
requestAnimationFrame(animate);
controls.update();
update();
composer.render();
}
animate();
性能优化
使用InstancedMesh
javascript
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ffff });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);
const dummy = new THREE.Object3D();
for (let i = 0; i < 1000; i++) {
dummy.position.set(
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100
);
dummy.scale.set(
Math.random(),
Math.random(),
Math.random()
);
dummy.rotation.set(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);
使用LOD
javascript
const lod = new THREE.LOD();
const highGeometry = new THREE.TorusKnotGeometry(10, 3, 100, 16);
const mediumGeometry = new THREE.TorusKnotGeometry(10, 3, 50, 8);
const lowGeometry = new THREE.TorusKnotGeometry(10, 3, 10, 4);
const material = new THREE.MeshStandardMaterial({ color: 0xff00ff });
lod.addLevel(new THREE.Mesh(highGeometry, material), 0);
lod.addLevel(new THREE.Mesh(mediumGeometry, material), 100);
lod.addLevel(new THREE.Mesh(lowGeometry, material), 200);
scene.add(lod);
总结
Three.js是一个功能强大的3D库,掌握高级材质和光照技术可以让你创建出令人惊叹的视觉效果。从简单的几何体到复杂的场景,Three.js都能胜任。
我的鬃狮蜥Hash对3D图形也有自己的理解------它总是能从不同角度观察蟋蟀,这也许就是自然界的"3D感知"吧!
如果你对WebGL或Three.js感兴趣,欢迎留言交流!我是欧阳瑞,极客之路,永无止境!
技术栈:Three.js · WebGL · 3D图形 · 着色器