Three.js 平面扫描效果 | 三维可视化 / AI 提示词

📋 AI 提示词

prompt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
使用 Three.js 实现【平面扫描效果】,具体要求:

【核心特效】
- 圆形扫描动画
- 透明度渐变效果
- 纹理遮罩处理

【场景与光照】
- 深灰色背景
- 纹理贴图应用
- 平面几何体

【交互与控制】
- OrbitControls 视角控制
- 扫描速度可调

【技术要求】
- Three.js 版本
- onBeforeCompile 着色器修改
- TextureLoader 纹理加载

🖼️ 效果预览

平面扫描效果

🎮 案例演示

立即体验


📖 效果拆解

层次 视觉效果 技术实现
基础 平面几何体 PlaneGeometry
核心特效 圆形扫描动画 onBeforeCompile 修改
增强细节 纹理遮罩 透明度检测 discard
动画效果 扫描线移动 时间驱动的半径变化

🔧 核心技术点

1. onBeforeCompile 修改

在现有材质上动态修改着色器:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
material.onBeforeCompile = (shader) => {
    // 添加自定义 uniforms
    Object.keys(uniforms).forEach((key) => shader.uniforms[key] = uniforms[key]);

    // 修改顶点着色器
    shader.vertexShader = shader.vertexShader.replace(`void main() {`,
        `varying vec2 vUv;
    varying vec3 v_position;
    void main() {
        vUv = uv;
        v_position = position;`
    );

    // 修改片段着色器
    shader.fragmentShader = shader.fragmentShader.replace(
        /#include <common>/,
        Object.keys(uniforms).map(i => 'uniform ' + uniforms[i].unit + ' ' + i + ';').join('\n') +
        '\n' + 'varying vec3 v_position; varying vec2 vUv;\n' + '\n#include <common>\n'
    );
}

2. 扫描效果实现

在片段着色器中实现圆形扫描:

glsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float dis = length(v_position - center);
vec4 diffuseColor;

if(dis < (innerCircleWidth + circleWidth) && dis > innerCircleWidth) {
    float r = (dis - innerCircleWidth) / circleWidth;
    float cOpacity = reverseOpacity ? (innerCircleWidth / circleMax) : 1. - (innerCircleWidth / circleMax);

    #ifdef USE_MAP
        vec3 textureColor = texture2D(map, vUv).rgb;
        if(isDisCard && textureColor.r < 0.1 && textureColor.g < 0.1 && textureColor.b < 0.1) discard;
    #endif

    diffuseColor = vec4(mix(diff, color3, r) * vec3(intensity, intensity, intensity),
                        opacity * cOpacity * opacityScale);
} else {
    if(isDisCard) discard;
    else diffuseColor = vec4(diffuse, opacity);
}

3. 动态扫描控制

在动画循环中更新扫描半径:

javascript
1
2
3
4
5
6
7
8
9
function animate() {
    // 扫描半径循环变化
    uniforms.innerCircleWidth.value < uniforms.circleMax.value
        ? uniforms.innerCircleWidth.value += uniforms.circleSpeed.value
        : uniforms.innerCircleWidth.value = 0;

    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
}

💡 调试与优化

问题类型 表现形式 解决方案
着色器替换失败 材质无变化 打印 shader 源码确认替换锚点
纹理加载失败 纹理不显示 检查纹理路径和跨域设置
透明度异常 扫描区域不透明 调整 opacityScale 参数
动画卡顿 帧率下降 减少 uniforms 更新频率

🚀 扩展思路

变体效果 核心改动 难度
多色扫描 添加多种颜色过渡 ⭐⭐
椭圆扫描 修改扫描形状为椭圆 ⭐⭐
交互控制 鼠标控制扫描位置 ⭐⭐
发光边缘 添加扫描线发光效果 ⭐⭐⭐

本文档由 ThreeLab 编辑整理,如需转载,请注明出处。