本文将介绍7种Three.js中实现轮廓线、边框线及物体选中效果的方法,并提供可直接运行的代码示例及性能评估。
方法1:后处理轮廓线(OutlinePass)
原理:使用后期处理通道检测深度/法线差异生成轮廓
优点:效果精准,支持复杂形状
缺点:性能消耗较大
<!DOCTYPE html>
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/OutlinePass.js"></script>
<script>
// 初始化场景
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建测试物体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
// 配置后处理
const composer = new THREE.EffectComposer(renderer);
composer.addPass(new THREE.RenderPass(scene, camera));
const outlinePass = new THREE.OutlinePass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
scene,
camera
);
outlinePass.edgeStrength = 5;
outlinePass.edgeGlow = 1;
outlinePass.visibleEdgeColor.set('#ff0000');
composer.addPass(outlinePass);
// 选中物体
outlinePass.selectedObjects = [cube];
function animate() {
requestAnimationFrame(animate);
composer.render();
}
animate();
</script>
</body>
</html>
方法2:法线扩展+材质叠加
原理:复制物体并放大,使用背面材质
优点:性能较好
缺点:不适合复杂拓扑
function createOutlineMesh(mesh, thickness = 0.1) {
const outlineMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
side: THREE.BackSide
});
const outlineMesh = new THREE.Mesh(mesh.geometry, outlineMaterial);
outlineMesh.scale.multiplyScalar(1 + thickness);
return outlineMesh;
}
// 使用示例
const baseCube = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshPhongMaterial());
const outlineCube = createOutlineMesh(baseCube);
baseCube.add(outlineCube);
scene.add(baseCube);
方法3:边缘几何体(EdgeGeometry)
原理:提取几何体边缘生成线模型
优点:精确控制边缘
缺点:内存占用较高
const geo = new THREE.EdgesGeometry(mesh.geometry);
const mat = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 2 });
const wireframe = new THREE.LineSegments(geo, mat);
mesh.add(wireframe);
方法4:自定义着色器(ShaderMaterial)
原理:在片元着色器中检测深度变化
优点:极致性能优化潜力
缺点:实现复杂度高
// 顶点着色器
varying vec3 vNormal;
void main() {
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
// 片元着色器
varying vec3 vNormal;
void main() {
float intensity = pow(1.0 - dot(vNormal, vec3(0,0,1)), 2.0);
gl_FragColor = vec4(1.0, 0.0, 0.0, intensity * 0.5);
}
方法5:模板缓冲区(Stencil Buffer)
原理:利用模板缓冲实现精确选中
优点:性能极佳
缺点:需要WebGL 2.0支持
renderer.stencilTest = true;
// 主物体
mesh.material.stencilWrite = true;
mesh.material.stencilRef = 1;
// 轮廓物体
outlineMesh.material.stencilWrite = false;
outlineMesh.material.stencilFunc = THREE.NotEqualStencilFunc;
方法6:CSS3D叠加边框
原理:使用CSS3DRenderer叠加div元素
优点:支持复杂CSS效果
缺点:3D坐标同步困难
const cssRenderer = new THREE.CSS3DRenderer();
const element = document.createElement('div');
element.style.border = '2px solid red';
new THREE.CSS3DObject(element).position.copy(mesh.position);
方法7:GPU加速边缘检测
原理:通过屏幕空间导数计算边缘
优点:屏幕空间统一处理
缺点:需要后处理支持
float depth = gl_FragCoord.z;
vec2 d = vec2(dFdx(depth), dFdy(depth));
float edge = sqrt(dot(d,d)) * 100.0;
if(edge > 0.1) {
gl_FragColor = vec4(1,0,0,1);
}
如何选择?
-
移动端优先:法线扩展或模板缓冲区
-
复杂模型:OutlinePass或EdgeGeometry
-
极致性能:自定义着色器方案
-
动态效果:GPU边缘检测
每种方法都有其适用场景,建议根据项目需求进行性能与效果权衡测试。
将以上代码保存为HTML文件并用现代浏览器打开即可直接查看效果,确保网络可访问Three.js CDN资源。