【Threejs学习】创建Threejs页面

学习文档地址:

threejs官网:https://threejs.org/

Threejs官网中文文档:https://threejs.org/docs/index.html#manual/zh/

threejs中文网:http://www.webgl3d.cn/

threejs基础教程:http://www.webgl3d.cn/pages/aac9ab/

webgl基础教程:http://www.webgl3d.cn/pages/9bc0db/

threejs数学几何计算:http://www.webgl3d.cn/pages/001888/

threejs shader:http://www.webgl3d.cn/pages/d30795/

blender基础:http://www.webgl3d.cn/pages/00cfc0/
学习文档下载:
https://gitee.com/xin_hu199/threejs-code-public

git clone https://gitee.com/xin_hu199/threejs-code-public.git

结构图:

threejs中有三个对象:

  1. 场景
  2. 相机
  3. 渲染器

一、场景 Scene

1.创建场景

bash 复制代码
  const scene = new THREE.Scene();

2.创建网络模型

2.1 几何体

立方体、球......

1.立方体-BoxGeometry(x, y, z)
bash 复制代码
const geometry = new THREE.BoxGeometry(5, 5, 5)

x:左右 const geometry = new THREE.BoxGeometry(10, 5, 5)

y:上下 const geometry = new THREE.BoxGeometry(5, 10, 5)

z:前后 const geometry = new THREE.BoxGeometry(5, 5, 10)

x: BoxGeometry(10, 5, 5) y: BoxGeometry(5, 10, 5) z: BoxGeometry(5, 5, 10)

2 球-SphereGeometry(5, 32, 16)
2.2 材质

创建几何体之后需要给它一个材质,让它有颜色。

Threejs自带了几种材质,每种材质都有相应的属性,如MeshBasicMaterial

1.MeshBasicMaterial

color:十六进制(hex colors)颜色格式

wireframe:是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)

bash 复制代码
 const materialBasic = new THREE.MeshBasicMaterial({
    color: '#4d72a9',
    wireframe: true
  })
2.3 网格 Mesh

网格包含一个几何体以及作用在此几何体上的材质,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。

bash 复制代码
const geometry = new THREE.BoxGeometry( 1, 1, 1 ); // 几何体
const materialBasic = new THREE.MeshBasicMaterial( { color: '#4d72a9' } ); // 材质
const cube = new THREE.Mesh( geometry, materialBasic ); // 网格
scene.add( cube );

注: 默认在调用 scene.add()时,物体会被添加到(0,0,0)坐标,使得摄像机和立方体在一起。为了防止这种情况的发生,我们需移动摄像机位置,如:camera.position.z = 5。

二、相机 Camera

1.相机类型

three.js 里有几种不同的相机:

  • 透视相机:PerspectiveCamera (透视投影)

模拟人眼视觉效果的相机,进大远小

  • 正交相机:OrthographicCamera(正射投影)

用于渲染2D场景的相机,无论物体距离相机有多远,相机看到的物体大小都会一致

这里使用 PerspectiveCamera(透视摄像机)

bash 复制代码
  const camera = new THREE.PerspectiveCamera(
    70, // 视野角度:在显示器上能看到的场景范围,单位是角度
    threeRef.value.clientWidth / threeRef.value.clientHeight, // 长宽比:宽 除以 高
    0.1, // 近截面
    1000 // 远截面,某些部分比摄像机的远截面或近截面近的时候,该部分不会被渲染到场景中
  )

构造器: new THREE.PerspectiveCamera( fov: Number, aspect: Number, near: Number, far: Number)
属性:

  • 视野角度 (FOV): 无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。默认值是50
  • 长宽比 (aspect ratio): 物体的宽除以它的高的值。通常是使用画布的宽/画布的高。默认值是1(正方形画布)
  • 近截面 (near)/远截面 (far): 当物体某些部分比摄像机的远截面 远或者比近截面近的时候,该这些部分将不会被渲染到场景中。

远截面:默认2000,该值必须大于近截面

近截面:默认0.1,该值在0---far之间,0对于透视摄像机来说不是有效值

  • 其他属性查看文档: filmGauge(胶片尺寸) 、filmOffset(偏移量)、zoom(缩放倍数)......

2.相机位置

语法: camera.position.set(x,y,z);

bash 复制代码
// 设置相机位置
camera.position.set(10, 10, 10)

注: 如果不设置相机位置,相机会默认在(0,0,0),需要调整相机位置防止摄像机和立方体彼此在一起,如:camera.position.z =5

3.相机视线方向

设置相机看向物体的方向(默认指向三维坐标系的原点)
语法: camera.lookAt(x,y,z);

bash 复制代码
//相机-视线方向:设置相机看向物体的方向(默认指向三维坐标系的原点)
camera.lookAt(0, 0, 0)

三、使用渲染器渲染场景

three.js 里提供了几种不同的渲染器:

  • WebGLRenderer

这里使用 WebGLRenderer 渲染器

bash 复制代码
  // 1 创建WebGLRenderer渲染器
  const renderer = new THREE.WebGLRenderer()
  // 2 通过setSize()方法设置渲染的长宽
  renderer.setSize(
    threeRef.value.clientWidth,
    threeRef.value.clientHeight,
    false
  )
  // 3 将渲染器renderer的dom元素(renderer.domElement)添加到页面中
  threeRef.value.appendChild(renderer.domElement)
  // 4 渲染
  renderer.render(scene, camera)

1.创建渲染器

语法: const renderer = new THREE.WebGLRenderer()

2.设置渲染器的尺寸

使用 setSize 传入渲染器的宽高,

bash 复制代码
 renderer.setSize(
    threeRef.value.clientWidth,
    threeRef.value.clientHeight,
    false
  )

3.渲染场景

添加"渲染循环 "(render loop)或者"动画循环"(animate loop)

bash 复制代码
function animate() {
	requestAnimationFrame( animate );
  // 使立方体动起来
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
	renderer.render( scene, camera );
}
animate();

四、总结

1.步骤

1.创建场景: const scene = new THREE.Scene();

2.创建相机:const camera = new THREE.PerspectiveCamera();

注1:相机默认位置会和几何体重叠,需要调整相机位置

3.创建立方体: const geometry = new THREE.BoxGeometry(2, 2, 2);

4.添加材质: const materialBasic = new THREE.MeshBasicMaterial({ color: '#4d72a9', wireframe: true });

5.创建网格,将立方体与材质放入: const cube = new THREE.Mesh(geometry, materialBasic);

注2:创建网格地面,添加到场景中

6.将内容添加到场景中:scene.add(cube);

7.创建渲染器: const renderer = new THREE.WebGLRenderer();

8.将渲染器添加到页面中:document.body.appendChild(renderer.domElement);

9.渲染场景,将场景及摄像机传入: renderer.render(scene, camera);

注3:第一个参数是场景,第二个参数是摄像机

10.添加动画循环,让立方体动起来

2.示例

示例一:

vue 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script type="module">
			import * as THREE from 'https://unpkg.com/three/build/three.module.js';
			
      // 1.创建场景
      const scene = new THREE.Scene();
      // 2.创建相机
      const camera = new THREE.PerspectiveCamera();
      camera.position.z = 10;
      camera.position.y = 2;
      // 3.创建立方体
      const geometry = new THREE.BoxGeometry();
      // 4.添加材质
      const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
      // 5.创建网格,将立方体和材质放入
      const cube = new THREE.Mesh(geometry, material);
      cube.position.set(0, 3, 0 )
      // 6.将内容添加到场景中
      scene.add(cube);
      // 7.创建渲染器
      const renderer = new THREE.WebGLRenderer();
      // 8.将渲染器添加到页面中
      document.body.appendChild(renderer.domElement);
      // 调整渲染器窗口大小
      renderer.setSize(window.innerWidth, window.innerHeight);
      
      // 添加网格地面
      const gridHelper = new THREE.GridHelper(10, 10);
      // 将网格地面添加到场景中
      scene.add(gridHelper);

      // 9.渲染场景,将场景和摄像机传入
      // renderer.render(scene, camera)

      // 10.让立方体动起来
      function animate() {
        requestAnimationFrame(animate); // 动画循环
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        renderer.render(scene, camera); 
      }
      animate();

// TODO: 画布自适应暂时无效果
window.addEventListener('resize', () => {
  // 更新摄像头比例
  camera.aspect = window.innerWidth / window.innerHeight
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix()
  // 渲染器大小
  renderer.setSize(
    window.innerWidth,
    window.innerHeight,
    false
  )
  // 设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio)
})

// 全屏
window.addEventListener('dblclick', () => {
  const fullScreenElement = document.fullscreenElement
  if (!fullScreenElement) {
    //让画布对象全屏
    renderer.domElement.requestFullscreen()
  } else {
    //退出全屏,使用document对象
    document.exitFullscreen()
  }
})

		</script>
	</body>
</html>


示例二:

vue 复制代码
<template>
  <div class="w-100% h-100%">
    <div ref="threeRef" class="w-100% h-100%"></div>
  </div>
</template>

<script setup>
// 引入three.js
import * as THREE from 'three'
import { onMounted, ref, reactive } from 'vue'

let threeRef = ref(null)
// 一、场景:创建场景(scene)
const scene = new THREE.Scene()
let camera = reactive()
const renderer = new THREE.WebGLRenderer()

onMounted(() => {
  initThree()
})

function initThree() {
  // 1.1 创建网络模型-几何体: 立方体-BoxGeometry(x, y, z)
  // const geometry = new THREE.SphereGeometry(5, 32, 16)
  const geometry = new THREE.BoxGeometry(2, 2, 2)
  // 1.2 创建网络模型-材质: Basic
  const materialBasic = new THREE.MeshBasicMaterial({
    color: '#4d72a9',
    wireframe: true, //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
  })

  // 1.3 创建一个网格模型对象:Mesh
  const cube = new THREE.Mesh(geometry, materialBasic) //网络模型对象Mesh
  // 1.4 把网格模型添加到三维场景
  scene.add(cube)

  // 1.4.3 修改几何体位置
  cube.position.set(0, 0, 0)
  camera = new THREE.PerspectiveCamera(
    70, // 视野角度:在显示器上能看到的场景范围,单位是角度
    threeRef.value.clientHeight / threeRef.value.clientWidth, // 摄像机视锥体长宽比(aspect)
    0.1, // 近截面
    1000 // 远截面,某些部分比摄像机的远截面或近截面近的时候,该部分不会被渲染到场景中
  )
  // 2.1 相机-位置:设置相机位置
  camera.position.set(10, 10, 10)
  // 2.2 相机-视线方向:设置相机看向物体的方向(默认指向三维坐标系的原点)
  camera.lookAt(0, 0, 0)
  //  防止摄像机和立方体彼此在一起
  // camera.position.z =5;

  // 三、渲染器
  // 3.1 创建WebGLRenderer渲染器

  // 3.2 通过setSize()方法设置渲染的长宽
  renderer.setSize(
    threeRef.value.clientWidth,
    threeRef.value.clientHeight,
    false
  )
  // 3.3 将渲染器renderer的dom元素(renderer.domElement)添加到页面中
  threeRef.value.appendChild(renderer.domElement)

  // 创建光源
  const spotLight1 = new THREE.SpotLight(0xffffff, 1) //(光照颜色, 光照强度)
  // 设置光源位置
  spotLight1.position.set(10, 10, 10)
  const spotLight2 = new THREE.SpotLight(0xffffff, 1) //(光照颜色, 光照强度)
  // 设置光源位置
  spotLight2.position.set(-10, -10, -10)
  // 将光源添加到场景中
  scene.add(spotLight1, spotLight2)
  // 为了方便观察3D图像,添加三维坐标系对象
  // const axes = new THREE.AxesHelper(8) // 坐标系轴长设置为8
  // 把三维坐标系 添加到场景中
  // scene.add(axes)

  // 五、渲染场景
  function animate() {
    //循环调用: 切换到其他页面时会暂停
    requestAnimationFrame(animate)
    // 让立方体动起来
    cube.rotation.x += 0.01
    cube.rotation.y += 0.01
    //渲染
    renderer.render(scene, camera)
  }
  animate()
}
</script>

<style lang="scss" scoped>
.my-three {
  width: 100%;
  height: 100%;
}
</style>
相关推荐
凹凸曼打不赢小怪兽10 分钟前
react 受控组件和非受控组件
前端·javascript·react.js
糊涂君-Q21 分钟前
Python小白学习教程从入门到入坑------第三十一课 迭代器(语法进阶)
python·学习·程序人生·考研·职场和发展·学习方法·改行学it
狂奔solar21 分钟前
分享个好玩的,在k8s上部署web版macos
前端·macos·kubernetes
qiyi.sky23 分钟前
JavaWeb——Web入门(8/9)- Tomcat:基本使用(下载与安装、目录结构介绍、启动与关闭、可能出现的问题及解决方案、总结)
java·前端·笔记·学习·tomcat
dal118网工任子仪43 分钟前
web安全漏洞之ssrf入门
笔记·学习·计算机网络·网络安全
清云随笔1 小时前
axios 实现 无感刷新方案
前端
鑫宝Code1 小时前
【React】状态管理之Redux
前端·react.js·前端框架
键盘敲没电1 小时前
【iOS】知乎日报前三周总结
学习·ios·objective-c·xcode
忠实米线1 小时前
使用pdf-lib.js实现pdf添加自定义水印功能
前端·javascript·pdf
pink大呲花1 小时前
关于番外篇-CSS3新增特性
前端·css·css3