Three.js 旋转半圆石碑特效

🎯 提示词

PROMPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
使用 Three.js 实现旋转半圆石碑特效,具体要求:

**核心特效**
- 平面上的半圆发光区域
- 旋转的指针状光柱
- 角度渐变透明度效果
- 动态旋转动画

**场景与光照**
- 半透明背景 (alpha: true)
- 坐标轴辅助线辅助调试
- OrbitControls 自由观察

**交互与控制**
- TrackballControls 旋转缩放
- Stats 性能监控面板

**技术要求**
- Three.js 版本 (ES Module)
- 自定义 ShaderMaterial
- 极坐标旋转计算
- Raymarching 角度检测算法

📖 效果拆解

层次 视觉效果 技术实现
基础 绿色半圆发光区域 Fragment shader 基于距离判断
核心特效 旋转指针光柱 rotatePoint 函数旋转端点
动态效果 持续旋转动画 uTime 控制角度变化
辅助功能 坐标轴辅助线 AxesHelper

🔧 核心技术点

1. 点旋转算法

为什么需要这个技术:将光柱端点绕中心旋转,计算任意时刻光柱的位置。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
vec2 rotatePoint(vec2 center, float angle, vec2 p) {
    float s = sin(angle);
    float c = cos(angle);
    // 平移到原点
    p.x -= center.x;
    p.y -= center.y;
    // 旋转
    float xNew = p.x * c - p.y * s;
    float yNew = p.x * s + p.y * c;
    // 移回原位
    return vec2(xNew + center.x, yNew + center.y);
}

2. 角度向量计算

为什么需要这个技术:计算像素点到圆心的向量与光柱向量的夹角,用于判断是否在光柱范围内。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float angleVec(vec2 a_, vec2 b_) {
    vec3 a = vec3(a_, 0);
    vec3 b = vec3(b_, 0);
    float dotProd = dot(a, b);
    vec3 crossprod = cross(a, b);
    float crossprod_l = length(crossprod);
    float lenProd = length(a) * length(b);
    float cosa = dotProd / lenProd;
    float sina = crossprod_l / lenProd;
    float angle = atan(sina, cosa);
    // 判断方向
    if (dot(vec3(0,0,1), crossprod) < 0.0)
        angle = 90.0;
    return angle * (180.0 / PI);
}

3. 半圆区域判断

为什么需要这个技术:结合距离和角度判断,决定像素是否发光。

GLSL
1
2
3
4
5
6
7
8
9
10
11
12
void main(){
    vec2 center = vec2(0.5, 0.5);
    float radius = 0.5;
    float angleStela = 180.0;  // 半圆角度
    float distanceToCenter = distance(center, vUv.xy);
    float angleStelaToApply = angleVec(normalize(lineEnd - center), normalize(vUv - center));
    // 在角度和半径范围内才发光
    if (angleStelaToApply < angleStela && distanceToCenter < radius) {
        float factorAngle = 1.0 - angleStelaToApply / angleStela;
        alpha = factorAngle * endAlpha;
    }
}

4. 旋转动画控制

为什么需要这个技术:通过时间 uniform 控制光柱持续旋转。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
function animate() {
    requestAnimationFrame(animate);
    if (rayMarchingFireMaterial) {
        rayMarchingFireMaterial.uniforms.uTime.value += 0.01;
    }
    controller.update(clock.getDelta());
    renderer.render(scene, camera);
    stats.update();
}

💡 调试与优化

问题类型 表现形式 解决方案
半圆变整圆 光柱两侧都发光 检查 angleStela 值是否为 180
光柱闪烁 帧率不稳定 减少 shader 中的 cross 计算
旋转方向错误 光柱向反方向旋转 检查 sin/cos 顺序或时间符号

🚀 扩展思路

变体效果 核心改动 难度
多指针时钟 增加多个不同角度的光柱
雷达扫描 渐变透明度模拟扫描效果
霓虹灯管 添加颜色渐变和发光效果 ⭐⭐
动态半径 radius 随时间变化 ⭐⭐
3D 半球星体 使用 SphereGeometry 替代 PlaneGeometry ⭐⭐⭐

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