【3D】three.js主体不动场景\背景旋转的方法

·  阅读 69

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

方法一 创建两个THREE对象分层控制

两个DIV,创建两个THREE对象,完全弄出两套

<div id="divBG"></div>
<div id="divZT"></div>
复制代码

divBG,绑定创建THREE对象1,在场景中添加背景图片,设置controls的自动旋转。

关键代码如下:

initScene () {
  // 场景作为一个容器
  scene = new THREE.Scene()
  let urls = ['dark-s_px.jpg', 'dark-s_nx.jpg', 'dark-s_py.jpg', 'dark-s_ny.jpg', 'dark-s_pz.jpg', 'dark-s_nz.jpg']
  let loader = new THREE.CubeTextureLoader()
  loader.setPath('/static/three/MilkyWay/')
  let background = loader.load(urls)
  scene.background = background
},
initControls () {
  controls = new OrbitControls(camera, renderer.domElement)
  controls.autoRotate = true // 是否自动旋转
  controls.autoRotateSpeed = 1.0 // 自动旋转的速度,默认值是 2.0,即渲染满60帧的情况下30秒旋转360度。
},
复制代码

注意camera、renderer等绑定的是divBG对应的dom。

divZT,绑定创建THREE对象2,场景不要设置背景,直接加载主体不需要转动的部分。

在此不赘述,重点在方法二。

方法二 场景旋转主体逆向旋转

全部绑定在一个DIV上实现,创建一个THREE对象,给其最外层场景设置背景,同时设置controls.autoRotate的自动旋转。

此时,整个场景里的对象都会旋转起来,为了让主体部分保持不动,只需设置主体部分进行逆向旋转即可。

关键步骤如下:

1、创建DIV

<div id="divOne"></div>
divOne = document.getElementById('divOne')
复制代码

2、创建外层场景并添加背景图片,创建子场景放置不旋转的对象

// 场景
initScene () {
  scene = new THREE.Scene()
  // 给当前场景容器添加背景图片
  let urls = ['dark-s_px.jpg', 'dark-s_nx.jpg', 'dark-s_py.jpg', 'dark-s_ny.jpg', 'dark-s_pz.jpg', 'dark-s_nz.jpg']
  let loader = new THREE.CubeTextureLoader()
  loader.setPath('/static/three/MilkyWay/')
  let background = loader.load(urls)
  scene.background = background
  // 创建一个groupNoRotate不随着场景旋转而旋转
  groupNoRotate = new THREE.Group()
  scene.add(groupNoRotate)
},
复制代码

3、添加灯光至外层场景,跟随背景旋转

// 灯光
initLight () {
  let ambientLight = new THREE.AmbientLight(0xffffff) // 环境光
  let directionalLight = new THREE.DirectionalLight(0xffffff, 0.1) // 平行光
  directionalLight.position.set(5, 10, 5)
  let pointLight = new THREE.PointLight(0xffffff) // 点光源
  pointLight.position.set(30, 10, 10)
  // 将光源加入场景 因为加入scene而不是groupNoRotate 所以光源也会自动转动
  scene.add(ambientLight)
  scene.add(directionalLight)
  scene.add(pointLight)
},
复制代码

4、设置控制器的自动旋转及自动旋转速度

// 控制器
initControls () {
  controls = new OrbitControls(camera, renderer.domElement)
  ……
  controls.autoRotate = true // 是否自动旋转
  controls.autoRotateSpeed = 1.0 // 自动旋转的速度,默认值是 2.0,即渲染满60帧的情况下30秒旋转360度。
  ……
},
复制代码

5、加载模型至内层场景groupNoRotate

// 模型加载
initModel () {
  // 实例化加载器
  let loader = new GLTFLoader()
  loader.load('/static/three/model/line.glb', function (obj) {
    if (groupNoRotate !== null) {
      groupNoRotate.add(obj.scene) // 此处需将模型加载到groupNoRotate中一同控制groupNoRotate逆旋转
    }
    console.log('loaded')
  }, function (xhr) {
    console.log(xhr.loaded, 'loading')
  }, function (error) {
    console.error(error, 'load error!')
  })
},
复制代码

6、场景动画,将内层场景y轴旋转设置为逆向旋转

// 场景动画
animate () {
  // 控制groupNoRotate里面的所有对象一起逆向旋转,场景在自动旋转,所以表现为不旋转
  if (groupNoRotate !== null) {
    groupNoRotate.rotation.y = groupNoRotate.rotation.y - Math.PI / (30 * 60)
  }
  controls.update()
  renderer.render(scene, camera)
  stop = requestAnimationFrame(this.animate)
},
复制代码

关键点

自动旋转的速度controls.autoRotateSpeed要和逆向旋转的角度groupNoRotate.rotation.y相抵消!!!

controls.autoRotateSpeed = 1.0 // 自动旋转的速度,默认值是 2.0,即渲染满60帧的情况下30秒旋转360度。
groupNoRotate.rotation.y = groupNoRotate.rotation.y - Math.PI / (30 * 60)
复制代码

经测试发现,groupNoRotate.rotation.y每次的减幅应该是Math.PI / (30 * 60) * autoRotateSpeed。

controls.autoRotateSpeed = k
groupNoRotate.rotation.y = groupNoRotate.rotation.y - Math.PI * k / (30 * 60)
复制代码

为什么呢?我不知道瞎蒙的试了几次中了,求解…………

效果截图

明显能看出背景在转动,而主体部分(蓝色线)保持不动。

在这里插入图片描述

在这里插入图片描述

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改