揭秘Phantom.land交互式网格与3D面部粒子系统的构建技术

本文深入解析Phantom.land网站如何利用React Three Fiber、GLSL着色器和GSAP构建动态交互网格与3D面部粒子系统,包含完整的代码实现细节和技术架构设计。

隐形力量:Phantom.land交互式网格与3D面部粒子系统的构建

技术栈选择

项目采用Next.js/React作为基础框架,结合React Three Fiber桥接DOM组件与WebGL上下文。样式系统使用自定义CSS组件和SASS。动画交互选用GSAP,因其支持跨DOM和WebGL组件的统一动画框架,并集成SplitText、CustomEase和ScrollTrigger等插件。

主页网格系统实现

网格架构

网格视图通过Three.js原生对象集成到React Three Fiber场景中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// GridView.tsx
const GridView = () => (
  <Canvas>
    <ProjectsGrid />
    <Postprocessing />
  </Canvas>
);

// ProjectsGrid.tsx
const ProjectsGrid = ({atlases, tiles}) => {
  const {canvas, camera} = useThree();
  const grid = useMemo(() => new Grid(canvas, camera, atlases, tiles), []);
  return <primitive object={grid} />;
}

后处理失真效果

通过自定义着色器通道实现动态失真效果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Postprocessing.tsx
const Postprocessing = () => {
  const {gl, scene, camera} = useThree();
  const {effectComposer, distortionShader} = useMemo(() => {
    const renderPass = new RenderPass(scene, camera);
    const distortionPass = new ShaderPass(new DistortionShader());
    const composer = new EffectComposer(gl);
    composer.addPass(renderPass);
    composer.addPass(distortionPass);
    composer.addPass(new OutputPass());
    return {effectComposer, distortionShader};
  }, []);

  useFrame(() => effectComposer.render(), 1);
}

GLSL失真着色器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// fragmentShader.glsl
uniform vec2 distortion;
void main() {
  vec2 shiftedUv = 2.0 * (vUv - 0.5);
  float distanceToCenter = length(shiftedUv);
  shiftedUv *= (0.88 + distortion * dot(shiftedUv));
  vec2 transformedUv = shiftedUv * 0.5 + 0.5;
  // 渐晕效果
  float vignetteIntensity = smoothstep(0.8, vignetteOffset*0.799, 
    (vignetteDarkness + vignetteOffset) * distanceToCenter);
  gl_FragColor = texture2D(tDiffuse, transformedUv) * vignetteIntensity;
}

交互功能实现

环境鼠标偏移

1
2
3
4
getAmbientCursorOffset() {
  const uv = this.navigation.pointerUv;
  return uv.subScalar(0.5).multiplyScalar(0.2);
}

拖拽缩放

1
2
3
4
5
6
7
animateCameraZ(distance: number, duration: number) {
  gsap.to(this.camera.position, {
    z: distance,
    duration,
    ease: CustomEase.create('cameraZoom', '.23,1,0.32,1')
  });
}

惯性拖拽

1
2
3
4
5
6
7
8
update() {
  if(this.isDragAction) {
    this.positionOffset.add(this.dragAction.clone());
  } else {
    this.positionOffset.add(this.velocity);
  }
  this.velocity.lerp(new Vector2(), 0.1);
}

3D面部粒子系统

粒子生成架构

使用280×280网格生成78,400个粒子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const FaceParticleSystem = ({ particlesData }) => (
  <points>
    <bufferGeometry>
      <bufferAttribute attach="attributes-position" args={[positions, 3]} />
      <bufferAttribute attach="attributes-vRandom" args={[randoms, 4]} />
    </bufferGeometry>
    <shaderMaterial
      fragmentShader={faceFrag}
      vertexShader={faceVert}
      uniforms={uniforms}
    />
  </points>
);

深度驱动粒子定位

1
2
3
4
// vertexShader.glsl
vec3 depthTexture = texture2D(depthMap, vIndex.xy).xyz;
float zDepth = (1. - depthValue.z);
pos.z = (zDepth * 2.0 - 1.0) * zScale;

颜色密度粒子缩放

1
2
3
vec3 colorTexture = texture2D(colorMap, vIndex.xy).xyz;
float density = (colorTexture.x + colorTexture.y + colorTexture.z) / 3.;
float pScale = mix(pScaleMin, pScaleMax, density);

动态噪声动画

1
pos += curlNoise(pos * curlFreq1 + time) * noiseScale * 0.1;

面部过渡动画

使用GSAP时间轴控制着色器参数:

1
2
3
timelineRef.current = gsap.timeline()
  .fromTo(uniforms.transition, {value: 0}, {value: 1.3, duration: 1.6})
  .to(uniforms.zScale, {value: particlesParams.face_scale_z, duration: 1.6}, 0);

自定义景深效果

1
2
3
4
5
6
7
vec4 viewPosition = viewMatrix * modelPosition;
vDistance = abs(focus + viewPosition.z);
gl_PointSize = pointSize * pScale * vDistance * blur * totalScale;

// 片段着色器
float alpha = (1.04 - clamp(vDistance * 1.5, 0.0, 1.0));
gl_FragColor = vec4(color, alpha);

技术挑战与解决方案

  • 面部尺度统一:通过手动校准每个面部的深度缩放、颜色密度平衡和焦点平面优化
  • 性能优化:使用256×256 WebP纹理(单张<15KB)保持轻量级
  • 视觉一致性:针对不同拍摄条件定制粒子参数:
1
2
3
4
5
particle_params: {
  offset_z: 0,           // 整体Z位置
  z_depth_scale: 0,      // 深度图缩放因子
  face_size: 0,          // 整体面部缩放
}

结语

该技术方案展示了如何通过精简的WebP纹理、自定义着色器材料和动画系统,将2D肖像转化为交互式3D图形,实现了高性能的视觉体验。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计