Three.js 官方案例01

185 阅读3分钟
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { ConvexGeometry } from 'three/addons/geometries/ConvexGeometry'
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'

let group, camera, scene, renderer

init()

function init() {
  scene = new THREE.Scene()

  renderer = new THREE.WebGLRenderer({antialias: true})
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setAnimationLoop(animate)
  document.body.append(renderer.domElement)

  camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000)
  camera.position.set(15, 20, 30)
  scene.add(camera)

  /**
   * OrbitControls(object: Camera, domElement: HTMLDOMDelement):可以使得相机围绕目标进行轨道运a动
   *   object:(必须)将要被控制的相机。该相机不允许是其他任何对象的子级,除非该对象是场景自身
   *   domElement:用于事件监听的HTML元素
   */
  const controls = new OrbitControls(camera, renderer.domElement)
  controls.minDistance = 20
  controls.maxDistance = 50
  /**
   * maxPolarAngle: 能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI
   */
  controls.maxPolarAngle = Math.PI /  2

  /**
   * AmbientLight(color: Color, intensity: Float):环境光会均匀的照亮场景中的所有物体;环境光不能用来投射阴影,因为它没有方向
   *   color:(可选)一个表示颜色的Color实例、字符串或数字,默认为一个白色(0xffffff)的Color对象
   *   intensity:(可选)光照的强度。默认值为1.
   */
  scene.add(new THREE.AmbientLight(0x666666))

  /**
   * PointLight(color: Color, intensity: Float, distance: Number, decay: Float):点光源;从一个点向各个方向发射的光源。该光源可以投射阴影
   *   color: (可选)一个表示颜色的Color的实例、字符串或数字,默认值为一个白色(0xffffff)的Color对象
   *   intensity:(可选)光照强度,默认值为1
   *   distance:光源照射的最大距离,默认值为0(无限远)
   *   decay:沿着光照距离的衰退凉。默认值为2
   */
  const light = new THREE.PointLight(0xffffff, 3, 0, 0.1)
  camera.add(light)

  /**
   * AxesHelper(size: Number):用于简单模拟3个坐标轴的对象;红色代表x轴,绿色代表y轴,蓝色代表z轴
   *   size:(可选)表示代表轴的线段长度。默认为1.
   */
  scene.add(new THREE.AxesHelper(20))

  const loader = new THREE.TextureLoader()
  const texture = loader.load('texture/sprite/disc.png')
  texture.colorSpace = THREE.SRGBColorSpace

  /**
   * Group:组;它几乎和Object3D是相同的,其目的是使得组中对象在语法上的结构更加清晰
   */
  group = new THREE.Group()
  scene.add(group)

  /**
   * DodecahedronGeometry(radius: Float, detail: Integer):十二面缓冲几何体
   *   radius: 十二面体的半径,默认值为1.
   *   detail:默认值为0.将这个值设为一个大于0的数值将会为它增加一些顶点,使其不再是一个十二面体
   */
  let dodecahedronGeometry = new THREE.DodecahedronGeometry(10)

  dodecahedronGeometry.deleteAttribute('normal')
  dodecahedronGeometry.deleteAttribute('uv')

  /**
   * mergeVertices(geometry: BufferGeometry, tolerance: Number) 
   *   geometry:用于合并顶点的BufferGeometry实例
   *   tolerance:要合并的顶点属性之间允许的最大差异
   * 返回一个新的BufferGeometry,其中包含将所有(在容差范围内的)具有相似属性的顶点合并而成的顶点
   */
  dodecahedronGeometry = BufferGeometryUtils.mergeVertices(dodecahedronGeometry)

  //顶点
  const vertices = []
  const positionAttribute = dodecahedronGeometry.getAttribute('position')

  /**
   * Vector3(x: Float, y: Float, z: Float):创建一个新的Vector3
   *   x:向量的x值,默认为0
   *   y:向量的y值,默认为0
   *   z:向量的z值,默认为0
   * 方法:
   *  .fromBufferAttribute(attribute: BufferAttribute, index: Integer):从attribute中设置向量的x值、y值和z值
   *     attribute: 来源的attribute
   *     index:在attribute中的索引
   */
  for(let i = 0; i < positionAttribute.count; i++) {
    const vertex = new THREE.Vector3()
    vertex.fromBufferAttribute(positionAttribute, i)
    vertices.push(vertex)
  }

  /**
   * PointsMaterial:点材质,Points使用的默认材质
   */
  const pointsMaterial = new THREE.PointsMaterial({
    color: 'red',
    size: 1,
    alphaTest: 0.5
  })

  /**
   * BufferGeometry:是面片、线或几何体的有效表述。包括顶点位置、面片索引、法向量、
   * 颜色值、UV坐标和自定义缓存属性值。使用BufferGeometry可以有效减少向GPU传输上述
   * 数据所需的开销。
   * setFromPoints(points: any):通过点队列设置该BufferGeometry的Attribute
   */
  const pointsGeometry = new THREE.BufferGeometry().setFromPoints(vertices)

  /**
   * Points(geometry: BufferGeometry, material: Material): 一个用于显示点的类。由WebGLRenderer渲染的点使用gl.POINTS
   *   geometry:(可选)是一个BufferGeometry的实例,默认值是一个新的BufferGeometry
   *   material: (可选)是一个对象,默认值是一个PointsMaterial
   */
  const points = new THREE.Points(pointsGeometry, pointsMaterial)
  group.add(points)

  /**
   * MeshLambertMaterial:一种非光泽表面的材质,没有镜面高光。
   * 该材质使用基于非物理的Lambertian模型来计算反射率。这可以很好地模拟一些表面,
   * 但不能模拟具有镜面高光的光泽表面
   */
  const meshMaterial = new THREE.MeshLambertMaterial({
    color: 'blue',
    opacity: 0.5,
    side: THREE.DoubleSide,
    transparent: true
  })

  /**
   * ConvexGeometry(points: Array): 凸包几何体;ConvexGeometry可被用于为传入的一组点生成凸包
   *   points:所得凸包中将包含一组Vector3
   */
  const meshGeometry = new ConvexGeometry(vertices)

  const mesh = new THREE.Mesh(meshGeometry, meshMaterial)
  group.add(mesh)

  window.addEventListener('resize', onWindowResize)
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
}

function animate() {
  // group.rotation.y += 0.05
  renderer.render(scene, camera)
}