3d

# 3d

# 1.优秀3d效果

3d芯片充电 (opens new window)

3d智慧城市 (opens new window)

3d地铁站 (opens new window)

3d小游戏 (opens new window)

3d书屋 (opens new window)

3d天猫邀请函H5 (opens new window)

# 2.simple-noise

问题1:simple-noise是什么?

  • simplex-noise.js 是 Javascript 中的一种快速的单纯形噪声实现。它可以在浏览器和 nodejs 上运行。
  • 一般需要配合canvas实现随机动画,如波浪翻滚,随机背景粒子变化等

问题2:simple-noise如何使用?

// 创建canvas并获取绘制
<canvas id="canvas"></canvas>
this.canvas = document.getElementById('canvas');
this.ctx = this.canvas.getContext('2d');
this.w = window.innerWidth;
this.h = window.innerHeight;
this.canvas.width = this.w;
this.canvas.height = this.h;
this.count = 80;
// 循环绘制图像
loop() {
    var This = this;
    function drawloop(){
        window.requestAnimationFrame(drawloop);
        This.ctx.clearRect(0,0,This.w,This.h);
        This.speedX = 0;
        // This.speedY += 0.001; //每次渲染需要更新波峰波谷值
        This.speedY += 0.001; //每次渲染需要更新波峰波谷值
        //连续绘制三次波浪线
        This.draw('rgba(239,119,87,0.35)',-100);
        This.draw('rgba(239,119,87,0.3)',20);
        This.draw('rgba(239,119,87,0.2)',60);
        This.draw('rgba(239,119,87,0.15)',100);
        This.draw('rgba(239,119,87,0.1)',140);
    }
    drawloop();
}
draw(color,index) {
    var amp = 100; //波浪幅度 可以通过函数传递参数更改不同的幅度
    this.ctx.beginPath();
    for(var i=0;i<=this.count;i++){
        this.speedX += 0.05;
        var x = i*(this.w/this.count);
        var y = this.h/3.5 + this.simplex.noise2D(this.speedX,this.speedY)*amp + index;
        this.ctx[i === 0 ? 'moveTo' : 'lineTo'](x,y);
        // console.log(this.simplex.noise2D(this.speedX,this.speedY)*100)
    }
    this.ctx.lineTo(this.w,-this.h);
    this.ctx.lineTo(0, -this.h);
    this.ctx.closePath();
    this.ctx.fillStyle = color;
    this.ctx.fill();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  • simplex-noise的引入和使用
// 引入simplex-noise
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.3.0/simplex-noise.min.js"></script>
// 定义simplex-noise
this.simplex = new SimplexNoise();
// 使用simplex-noise,使用noise2D
var y = this.h/3.5 + this.simplex.noise2D(this.speedX,this.speedY)*amp + index;
1
2
3
4
5
6

问题3:simplex-noise如何在里面画波浪的?

  • 通过遍历,形成曲线,速度由0,遍历80次,每次增加0.05,增加到4。
  • x轴为每次的数据n,乘以视口宽度1920除以遍历总数80,x最大为视口宽度
  • y轴为视口高度1080除以3.5,加上noise2D的x和y轴速度移动的波峰和波谷值,乘以100,波浪幅度,加上index起始偏移
  • y类似于asin(x) + b
  • 图像上的自然曲线是noise 生成的,随机生成,用到一种叫 Berlin Noise 的算法,Berlin Noise 是一个非常强大的算法,常用于生成随机内容

问题4:simplex-noise如何画粒子系统的?

# 3.3d max常用快捷键

  • 顶视图:T
  • 底势图:B
  • 前视图:F
  • 左视图:L
  • 右视图:R
  • 透视图:P
  • 移动视图:鼠标中键
  • 旋转视图:alt + 鼠标中键
  • 缩放视图:ctrl + alt + 鼠标中键
  • 视图切换:alt + w

# 4.常见keycode

  • 前—w—87—上38,up
  • 后—s—83—下40,down
  • 左—a—65—左37,left
  • 右—d—68—右,39,right

# 5.执法人员在道路上来回巡逻的动画,如何实现的?

  • 参考案例代码地址:https://github.com/tweenjs/tween.js/blob/master/examples/00_hello_world.html
  • to(点坐标,时间/毫秒)—多少毫秒内移动到点坐标位置
  • start()—启动动画
  • chain() —链式补间—上一个补间结束,立即启动另一个补间动画
  • 无线来回核心代码—ween_zfr.chain(tween_zfr_back); tween_zfr_back.chain(tween_zfr);

# 6.环卫工人在道路上环圈打扫的动画,如何实现的?

  • 起始和结束的点位相同,形成闭环

# 7.模型进行场景漫游,点击屏幕位置,模型走到该位置,我是如何实现的?

  • 引入tween,
  • 创建光线投影
var raycaster = new THREE.Raycaster();//光线投射,用于确定鼠标点击位置
1
  • mousedown触发,点击屏幕坐标,二维转3d坐标三维
window.addEventListener("mousedown",mousedown);//页面绑定鼠标点击事件
mouse.x =  e.clientX / renderer.domElement.clientWidth*2-1;
mouse.y =  -(e.clientY / renderer.domElement.clientHeight*2)+1;
//以camera为z坐标,确定所点击物体的3D空间位置
 raycaster.setFromCamera(mouse,camera);
1
2
3
4
5
  • 获取点击的点,起始点位
//确定所点击位置上的物体数量
var intersects = raycaster.intersectObjects(scene.children);
//选中后进行的操作
if(intersects.length) {
    // 获取点击的点位
    // 起始点位
    let points = intersects[0].point
}
1
2
3
4
5
6
7
8
  • 获取加载的模型
// 获取场景中机器人模型
let rootModel = scene.children[5]
1
2
  • 创建及开启动画
// 创建动画
var tween = new TWEEN.Tween(rootModel.position);
// 运动到选择的位置
tween.to({ x: points.point.x, y: points.point.y, z: points.point.z }, 10000).start()
.onComplete(()=> {
    tween.stop() // 停止

    rootModel.position.x  = points.point.x
    rootModel.position.y  = points.point.y
    rootModel.position.z  = points.point.z

    // 在加入的机器人模型中找到Running动画,将其停止
    // 结束,使用Idle动画
    // const animationClip2 = rootModel.animations.find(animationClip => animationClip.name === "Idle");
    // console.log(rootModel, animationClip2, 'animationClip222')
    // const action3 = animationMixer.clipAction(animationClip2);
    // // 播放Idle动画
    // action3.pause()
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

扩展:如何实现模型走动有跑起来动画,停止时处于停止动画的?

  • 创建模型动画
// 动画
var animationMixer = new THREE.AnimationMixer(scene);
1
2
  • 找到所有播放的动画事件
 // 起始,使用Idle动画,Running
const animationClip = obj.animations.find(animationClip => animationClip.name === "Running");
1
2
  • 播放绑定动画,进行播放
const action2 = animationMixer.clipAction(animationClip);
// 1.0倍速度播放
action2.timeScale = 7.5//24帧每秒变为30帧每秒,要慢放为0.8倍,做动画要做30帧/s的
//调用播放器的播放事件
action2.play();
1
2
3
4
5

# 8.模型贴合问题?

  • fbx的模型贴合问题?--obj.children[0].material[i].depthWrite = false
  • glb模型贴合问题?--glb.scene.children[0].children[2].children[i].material.depthWrite = false