WebGL入门:Three.js高级材质与光照

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图形 · 着色器

相关推荐
互联圈运营观察2 小时前
区块链安全提醒:如何应对2026年钱包交互风险?
安全·区块链
Richown4 小时前
实时数据处理:Apache Kafka与Flink实战
区块链·react
啊哈哈1213816 小时前
系统设计复盘:为什么 Agent 的 ReAct 循环必须内嵌确定性保护层——以 FitMind 健康助手的路由与步骤控制为例
人工智能·python·react
11年老程序猿在线搬砖16 小时前
联盟链开发完全指南:从Hyperledger到FISCO BCOS,企业级区块链怎么选?
区块链·溯源联盟链·供应链溯源
Richown17 小时前
微前端架构:从理论到实践
区块链·react
多年小白18 小时前
兆易创新分析
大数据·人工智能·ai·金融·区块链
Richown21 小时前
数据可视化:使用D3.js创建交互式图表
区块链·react
liudanzhengxi1 天前
ImToken智能合约交互避坑指南
区块链
Richown1 天前
微服务通信:gRPC与REST对比分析
区块链·react