threejs学习记录

1.第一个threejs程序

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>第一个three.js文件_WebGL三维场景</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
      /* 隐藏body窗口区域滚动条 */
    }
  </style>
  <!--引入three.js三维引擎-->
  <script src="three.js-master/build/three.js"></script>
  <!-- <script src="./three.js"></script> -->
  <!-- <script src="http://www.yanhuangxueyuan.com/threejs/build/three.js"></script> -->
</head>
<body>
  <script>
    /**
     * 创建场景对象Scene
     */
    var scene = new THREE.Scene()
    //创建一个坐标轴
    var axes = new THREE.AxesHelper(100, 100, 100)
    scene.add(axes)
    /**
     * 创建网格模型
     */
    // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    var geometry = new THREE.BoxGeometry(100, 100, 100) //创建一个立方体几何对象Geometry
    var material = new THREE.MeshLambertMaterial({
      color: 0x0000ff    //材质的颜色
    }) //材质对象Material
    var mesh = new THREE.Mesh(geometry, material) //网格模型对象Mesh
    scene.add(mesh) //网格模型添加到场景中
    /**
     * 光源设置
     */
    //点光源
    var point = new THREE.PointLight(0xffffff) //光照强度
    point.position.set(100, 200, 300) //点光源位置
    scene.add(point) //点光源添加到场景中
    //环境光
    var ambient = new THREE.AmbientLight(0x444444)  //光照强度
    scene.add(ambient)
    // console.log(scene)
    // console.log(scene.children)
    /**
     * 相机设置
     */
    var width = window.innerWidth //窗口宽度
    var height = window.innerHeight //窗口高度
    var k = width / height //窗口宽高比
    var s = 200 //三维场景显示范围控制系数,系数越大,显示的范围越大
    //创建相机对象
    var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000)  //正向投影  前四个参数为拍照的窗口大小,后两个参数是拍照的距离大小从1-1000
    camera.position.set(200, 300, 200) //设置相机位置
    camera.lookAt(scene.position) //设置相机方向(指向的场景对象)
    /**
     * 创建渲染器对象
     */
    var renderer = new THREE.WebGLRenderer()
    renderer.setSize(width, height)//设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 1) //设置背景颜色
    document.body.appendChild(renderer.domElement) //body元素中插入canvas对象
    //执行渲染操作   指定场景、相机作为参数
    renderer.render(scene, camera);
  </script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IqQKbisa-1654054698304)(C:\Users\hutao\AppData\Local\Temp\1652758412516.png)]

基本原理:

分别使用构造函数THREE.Scene()THREE.OrthographicCamera()THREE.WebGLRenderer()创建了场景、相机、渲染器三个最顶层的总对象,然后通过总对象的子对象、方法和属性进行设置, 相机对象和渲染对象相对简单,最复杂的是场景对象,new THREE.Mesh(box,material);使用构造函数Mesh()创建了一个网格模型对象,该对象把上面两行含有顶点位置信息的几何体对象和含有颜色信息的材质对象作为参数,网格模型创建好之后, 需要使用场景对象的方法.add()把三维场景的子对象添加到场景中,new THREE.PointLight(0xffffff);new THREE.AmbientLight(0x444444);定义了两个点光源、环境光对象,然后作为场景的子对象插入场景中。 场景、相机、渲染器设置完成后,设置代码renderer.render(scene,camera)把场景、相机对象作为渲染器对象方法render()的参数,这句代码的意义相当于告诉浏览器根据相机的放置方式拍摄已经创建好的三维场景对象。

2.坐标系及变换操作

/**
     * 创建场景对象Scene
     */
    var scene = new THREE.Scene()
    //创建一个坐标轴
    var axes = new THREE.AxesHelper(100)  ///红线是X轴,绿线是Y轴,蓝线是Z轴  参数为坐标轴线的长度
    scene.add(axes)
    /**
     * 创建网格模型
     */
    // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    var geometry = new THREE.BoxGeometry(100, 100, 100) //创建一个立方体几何对象Geometry
    var material = new THREE.MeshLambertMaterial({
      color: 0x0000ff    //材质的颜色
    }) //材质对象Material
    var mesh = new THREE.Mesh(geometry, material) //网格模型对象Mesh
    scene.add(mesh) //网格模型添加到场景中
	mesh.position.set(10,10,10) //设置网格体的三位坐标点
	mesh.rotation.z = 45 / 180 * Math.PI  //网格体沿着z轴旋转45度
	mesh.rotation.x = 45 / 180 * Math.PI
	mesh.rotation.y = 45 / 180 * Math.PI
	mesh.scale.x=0.5 //网格体x轴方向缩放0.5倍
	mesh.scale.y=0.5
	mesh.scale.z=0.5
	mesh.scale.set(0.5,0.5,0.5)

3.运动的几种方式

 //SetInterval  是一个周期性函数,就像一个定时器,每隔多少毫秒ms执行一次某个函数
    setInterval(() => {
      mesh.rotation.z += 0.01
      //执行渲染操作   指定场景、相机作为参数
      renderer.render(scene, camera)
    }, 1000 / 60) //60帧刷新率的浏览器会比较流程,但是其中没有算程序执行的时间,一般不用这个函数


    //实际开发中,为了更好的利用浏览器渲染,可以使用函数requestAnimationFrame()代替setInterval()函数,
    //requestAnimationFrame()和setInterval()一样都是浏览器window对象的方法。

    function tick () {  //更流畅
      mesh.rotation.x += 0.01
      //执行渲染操作   指定场景、相机作为参数
      renderer.render(scene, camera)
      requestAnimationFrame(tick) //参数为函数本身
    }
    tick()

    //解决不同浏览器刷新率不同的问题
    var time = Date.now()
    function tick1 () {  //更流畅
      var currentTime = Date.now()
      var deltaTime = currentTime - time
      time = currentTime
      mesh.rotation.y += deltaTime * 0.001
      //执行渲染操作   指定场景、相机作为参数
      renderer.render(scene, camera)
      requestAnimationFrame(tick) //参数为函数本身
    }
    tick1()

    var clock = new THREE.Clock()  //threejs提供的一个构造函数生成一个clock对象
    tick2()
    function tick2 () {
      var time1 = clock.getElapsedTime()  //通过clock对象的getElapsedTime()产生一个均匀增长的时间值
      // console.log(time1)
      mesh.rotation.z = time1
      mesh.position.x = Math.sin(time1)
      mesh.position.y = Math.cos(time1)
      requestAnimationFrame(tick2) //参数为函数本身
      //执行渲染操作   指定场景、相机作为参数
      renderer.render(scene, camera)
    }

4.添加帧率检测器

import Stat from “three/examples/jsm/libs/stats.module.js”

this.stats =new Stat()

element.appendChild(this.stats.dom)

this.stats.update()

注后续在vue中进行学习

<template>
  <div>
    <div id="container" />
  </div>
</template>
<script>
import * as THREE from 'three'
import { FirstPersonControls } from 'three/examples/jsm/controls/FirstPersonControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import Stat from "three/examples/jsm/libs/stats.module.js"
export default {
  data() {
    return {
      publicPath: process.env.BASE_URL,
      mesh: null,
      camera: null,
      scene: null,
      renderer: null,
      firstPersonControls: null,
      clock: null,
      stats:null,
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    // 初始化
    init() {
      this.createScene() // 创建场景
      this.loadObj() // 加载OBJ模型
      this.createLight() // 创建光源
      this.createCamera() // 创建相机
      this.createRender() // 创建渲染器
      this.createFlyControls() // 创建第一人称控件
      this.render() // 渲染
    },
    // 创建场景
    createScene() {
      this.scene = new THREE.Scene()
      //创建一个坐标轴
      var axes = new THREE.AxesHelper(10000, 10000, 1000)
      this.scene.add(axes)
      //初始化帧率显示器
      this.stats =new Stat()
    },
    loadObj() {
      const THIS = this
      const loader = new GLTFLoader()
      loader.load(`${THIS.publicPath}sanjiang/sanjiang.gltf`, model => {
        model.scene.children[0].scale.set(100, 100, 100)
        this.scene.add(model.scene.children[0])
      })
    },
    setRandomColors(object, THIS) {
      const children = object.children

      if (children && children.length > 0) {
        children.forEach(function(e) {
          THIS.setRandomColors(e, THIS)
        })
      } else {
        if (object instanceof THREE.Mesh) {
          const colorIndex = Math.floor(Math.random() * 3) // 0~2的随机数
          const colorArray = [
            new THREE.Color(0xff0000),
            new THREE.Color(0x00ff00),
            new THREE.Color(0x0000ff)
          ]
          object.material.emissive = colorArray[colorIndex]
          object.material.color = colorArray[colorIndex]
          object.material.transparent = true
          object.material.opacity = 0.3
        }
      }
    },
    // 创建光源
    createLight() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff,2) // 创建环境光
      this.scene.add(ambientLight) // 将环境光添加到场景

      const spotLight1 = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight1.position.set(1500,1500, 1500)
      spotLight1.castShadow = true
      const spotLight2 = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight2.position.set(1500,0, 1500)
      spotLight2.castShadow = true
      const spotLight3 = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight3.position.set(0,1500, 1500)
      spotLight3.castShadow = true
      const spotLight4 = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight4.position.set(1500,1500, 0)
      spotLight4.castShadow = true
      this.scene.add(spotLight1,spotLight2,spotLight3,spotLight4)
    },
    // 创建相机
    createCamera() {
      const element = document.getElementById('container')
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      const k = width / height // 窗口宽高比
      // PerspectiveCamera( fov, aspect, near, far )
      this.camera = new THREE.PerspectiveCamera(35, k, 0.1, 100000)
      this.camera.position.set(-10000, 12000, -12000) // 设置相机位置
      this.camera.lookAt(new THREE.Vector3(0, 0, 0)) // 设置相机方向
      this.scene.add(this.camera)
    },
    // 创建渲染器
    createRender() {
      const element = document.getElementById('container')
      this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
      this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
      this.renderer.shadowMap.enabled = true // 显示阴影
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
      this.renderer.setClearColor(0x3f3f3f, 1) // 设置背景颜色
      element.appendChild(this.renderer.domElement)
      element.appendChild(this.stats.dom)   //把帧率加载到dom中
    },

    render() {
      const delta = this.clock.getDelta() //获取自上次调用的时间差
      this.firstPersonControls.update(delta) //更新第一人称控件
      this.stats.update()      //更新帧率
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
    // 创建第一人称控件
    createFlyControls() {
      this.clock = new THREE.Clock()
      this.firstPersonControls = new FirstPersonControls(
        this.camera,
        this.renderer.domElement
      )

      this.firstPersonControls.lookSpeed = 0.2 //鼠标移动查看的速度
      this.firstPersonControls.movementSpeed = 10 //相机移动速度
      this.firstPersonControls.noFly = true
      this.firstPersonControls.lookVertical = true
      this.firstPersonControls.constrainVertical = true //约束垂直
      this.firstPersonControls.verticalMin = 1.0
      this.firstPersonControls.verticalMax = 2.0
      this.firstPersonControls.lon = -150 //进入初始视角x轴的角度
      this.firstPersonControls.lat = 120 //初始视角进入后y轴的角度
    }
  }
}
</script>
<style>
#container {
  position: absolute;
  width: 100%;
  height: 100%;
}
</style>

5.OrbitControls鼠标交互

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

render() {
      const delta = this.clock.getDelta() //获取自上次调用的时间差
      this.OrbitControls.update(delta) //更新第一人称控件
      this.stats.update()
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
// 创建鼠标控件
    createOrbitControls() {
      this.clock = new THREE.Clock()
      this.OrbitControls = new OrbitControls(
        this.camera,
        this.renderer.domElement
      )
    }

鼠标控件的详细:

鼠标左键:方向旋转

滚轮:模型缩放

鼠标右键:模型平移

6.物体的组合运动group

// var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    var geometry1 = new THREE.BoxGeometry(100, 100, 100) //创建一个立方体几何对象Geometry
    var material1 = new THREE.MeshLambertMaterial({
      color: 0x0000ff    //材质的颜色
    }) //材质对象Material
var code1 = new THREE.Mesh(geometry, material) //网格模型对象Mesh
// var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    var geometry2 = new THREE.BoxGeometry(100, 100, 100) //创建一个立方体几何对象Geometry
    var material2 = new THREE.MeshLambertMaterial({
      color: 0x0000ff    //材质的颜色
    }) //材质对象Material
var code2 = new THREE.Mesh(geometry, material) //网格模型对象Mesh
// var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    var geometry3 = new THREE.BoxGeometry(100, 100, 100) //创建一个立方体几何对象Geometry
    var material3 = new THREE.MeshLambertMaterial({
      color: 0x0000ff    //材质的颜色
    }) //材质对象Material
var code3 = new THREE.Mesh(geometry, material) //网格模型对象Mesh
var group1 = new THREE.group()
group1.add(cube1,cube2)
var group2 = new THREE.group()
group2.add(group1)
var group3 = group2.clone() //可以复制group

此时cube1和chube2是一个组合相当于一个物体,可结合月亮、地球、太阳的自转公转情况理解

var group3 = group2.clone() 克隆group

应用---->制造一个小车

//材质
const material = new THREE.MeshNormalMaterial()
//Objects
//整个汽车 car - group
const car = new THREE.Group()
//车身 body - group
const body = new THREE.Group()
const bodyCube1 = new THREE.Mesh(
    new THREE.BoxGeometry(1, 2, 0.5),
    material
)
const bodyCube2 = new THREE.Mesh(
    new THREE.BoxGeometry(0.5, 0.5, 0.5),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
bodyCube2.position.z = 0.5
body.add(bodyCube1)
body.add(bodyCube2)
car.add(body)
//轮子1 - group
const wheelGroup1 = new THREE.Group()
const wheel1 = new THREE.Mesh(
    new THREE.BoxGeometry(0.1, 0.7, 0.7),
    material
)
wheelGroup1.position.set(-0.7, 0.6, 0)
wheelGroup1.add(wheel1)
car.add(wheelGroup1)
//轮子2 - group
const wheelGroup2 = new THREE.Group()
const wheel2 = new THREE.Mesh(
    new THREE.BoxGeometry(0.1, 0.7, 0.7),
    material
)
wheelGroup2.position.set(0.7, 0.6, 0)
wheelGroup2.add(wheel2)
car.add(wheelGroup2)
//轮子3 - group
const wheelGroup3 = wheelGroup1.clone()
wheelGroup3.position.y = -0.6
car.add(wheelGroup3)
//轮子4 - group
const wheelGroup4 = wheelGroup2.clone()
wheelGroup4.position.y = -0.6
car.add(wheelGroup4)
//轮胎 - group
const circle = new THREE.Group()
let n = 20
for (let i = 0; i < n; i++) {
    let r = 0.5
    const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.2)
    const mesh = new THREE.Mesh(geometry, material)
    mesh.position.x = r * Math.cos(Math.PI * 2 / n * i)
    mesh.position.y = r * Math.sin(Math.PI * 2 / n * i)
    circle.add(mesh)
}
circle.rotation.y = -0.5 * Math.PI
wheelGroup1.add(circle)
wheelGroup2.add(circle.clone())
wheelGroup3.add(circle.clone())
wheelGroup4.add(circle.clone())
scene.add(car)

7.基本Geometry

见官网详细BoxGeometry – three.js docs (threejs.org) 所有基本Geometry的基本属性

立方体

虽然这一形状的名字叫立方体(CubeGeometry),但它其实是长方体,也就是长宽高可以设置为不同的值。其构造函数是:

THREE.CubeGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)

这里,width是x方向上的长度;height是y方向上的长度;depth是z方向上的长度;后三个参数分别是在三个方向上的分段数,如widthSegments为3的话,代表x方向上水平分为三份。一般情况下不需要分段的话,可以不设置后三个参数,后三个参数的缺省值为1

**注意:**这个分段是对六个面进行分段,而不是对立方体的体素分段,因此在立方体的中间是不分段的,只有六个侧面被分段。

平面

这里的平面(PlaneGeometry)其实是一个长方形,而不是数学意义上无限大小的平面。其构造函数为:

THREE.PlaneGeometry(width, height, widthSegments, heightSegments)

其中,width是x方向上的长度;height是y方向上的长度;后两个参数同样表示分段。如果需要创建的平面在x轴和z轴所在的平面内,可以通过物体的旋转来实现

球体

球体(SphereGeometry)的构造函数是:

THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, thetaStart, thetaLength)

其中,radius是半径;segmentsWidth表示经度上的切片数;segmentsHeight表示纬度上的切片数;phiStart表示经度开始的弧度;phiLength表示经度跨过的弧度;thetaStart表示纬度开始的弧度;thetaLength表示纬度跨过的弧度。

分段

segmentsWidth相当于经度被切成了几瓣,而segmentsHeight相当于纬度被切成了几层。因为在图形底层的实现中,并没有曲线的概念,曲线都是由多个折线近似构成的。对于球体而言,当这两个值较大的时候,形成的多面体就可以近似看做是球体了

经度弧度
new THREE.SphereGeometry(3, 8, 6, Math.PI / 6, Math.PI / 3)

表示起始经度为Math.PI / 6,经度跨度为Math.PI / 3,需要注意的是,这里segmentsWidth为8意味着对于经度从Math.PI / 6跨过Math.PI / 3的区域内划分为8块,而不是整个球体的经度划分成8块后再判断在此经度范围内的部分

圆形

圆形(CircleGeometry)可以创建圆形或者扇形,其构造函数是:

THREE.CircleGeometry(radius, segments, thetaStart, thetaLength)
圆柱体

圆柱体(CylinderGeometry)的构造函数是:

THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded)

其中,radiusTop与radiusBottom分别是顶面和底面的半径,由此可知,当这两个参数设置为不同的值时,实际上创建的是一个圆台;height是圆柱体的高度;radiusSegments与heightSegments可类比球体中的分段;openEnded是一个布尔值,表示是否没有顶面和底面,缺省值为false,表示有顶面和底面。

标准圆柱体
new THREE.CylinderGeometry(2, 2, 4, 18, 3)

创建一个顶面与底面半径都为2,高度为4的圆柱体

正四面体、正八面体,正十二面体

正四面体(TetrahedronGeometry)、正八面体(OctahedronGeometry)、正二十面体(IcosahedronGeometry)的构造函数较为类似,分别为:

THREE.TetrahedronGeometry(radius, detail)
THREE.OctahedronGeometry(radius, detail)
THREE.IcosahedronGeometry(radius, detail)

其中,radius是半径;detail是细节层次(Level of Detail)的层数,对于大面片数模型,可以控制在视角靠近物体时,显示面片数多的精细模型,而在离物体较远时,显示面片数较少的粗略模型,一般可以对这个值缺省。

圆环面

圆环面(TorusGeometry)就是甜甜圈的形状,其构造函数是:

THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)

其中,radius是圆环半径;tube是管道半径;radialSegments与tubularSegments分别是两个分段数;arc是圆环面的弧度,缺省值为Math.PI * 2

圆环节

如果说圆环面是甜甜圈,那么圆环结(TorusKnotGeometry)就是打了结的甜甜圈,其构造参数为:

THREE.TorusKnotGeometry(radius, tube, radialSegments, tubularSegments, p, q, heightScale)

heightScale是在z轴方向上的缩放

用官网材质制造一个小车

//公共的材质
const m = new THREE.MeshNormalMaterial()
//car 整个汽车 group
const car = new THREE.Group()
//两面两个轮子 frontWheels - group
const frontWheels = new THREE.Group()
//轮子1 wheel1 - group
const wheel1 = new THREE.Group()
const wheelG = new THREE.TorusGeometry(0.5, 0.1, 10, 20)
const wheel1Mesh = new THREE.Mesh(wheelG, m)
const n = 10
for (let i = 0; i < n; i++) {
    const g = new THREE.CylinderGeometry(0.03, 0.03, 1)
    const mesh = new THREE.Mesh(g, m)
    mesh.rotation.z = Math.PI * 2 / n * i
    wheel1.add(mesh)
}
wheel1.add(wheel1Mesh)
//车轴1
const len = 2
const cylinderG = new THREE.CylinderGeometry(0.05, 0.05, len)
const cylinder = new THREE.Mesh(cylinderG, m)
cylinder.rotation.x = - 0.5 * Math.PI
wheel1.position.z = -len / 2
//轮子2 wheel2
const wheel2 = wheel1.clone()
wheel2.position.z = len / 2
frontWheels.add(wheel1, cylinder, wheel2)
frontWheels.rotation.y = 0.5 * Math.PI
frontWheels.position.y = -1
//后面的两个轮子 backWheels 
const backWheels = frontWheels.clone()
backWheels.position.y = 1
//************************* */
//车身 body group
const body = new THREE.Group()
const cubeG = new THREE.BoxGeometry(1.6, 3.4, 0.5)
const cube = new THREE.Mesh(cubeG, m)
//车顶
const roofG = new THREE.CylinderGeometry(1.4, 1.4, 1.6, 3, 1, false, -Math.PI / 2, Math.PI);
const roof = new THREE.Mesh(roofG, m)
roof.rotation.z = Math.PI / 2
roof.position.z = -0.2
body.add(cube, roof)
car.add(frontWheels, backWheels, body)
scene.add(car)
//地面
const planeG = new THREE.PlaneGeometry(20, 20)
const planeM = new THREE.MeshBasicMaterial({ color: 0xcccccc })
const plane = new THREE.Mesh(planeG, planeM)
scene.add(plane)
plane.rotation.x = -0.5 * Math.PI
car.rotation.x = -0.5 * Math.PI
car.position.y = 0.6

8.图像控制界面datGUI

npm install dat.gui

import * as dat from "dat.gui"
//初始化 图形控制界面 datGUI
this.gui = new dat.GUI()
this.gui.add(this.camera.position,"x",-5,5,0.1).name("相机的位置x")  
this.gui.add(this.camera.position,"y",-5,5,0.1).name("相机的位置y")
this.gui.add(this.camera.position,"z",-5,5,0.1).name("相机的位置z")
/// gui.add( obj对象 , "obj的属性",-5,5(控制的范围),步进).name("控制器重命名")
//只能控制对象里的属性值
//如果没有控制的范围就是一个单选
//如果没有对象的属性,就是一个按钮(可以用来执行对象里的某个函数)

注意:three.js中物体的颜色color是个对象,不能直接赋值,可以用cube.color.set( )或者cube.color = new THREE.color( )来设置

9.基本材质Material

见官网详细MeshBasicMaterial – three.js docs (threejs.org) 所有基本Material的基本属性

常见材质
MeshBasicMaterial(网格基础材质)可赋予简单颜色
MeshDepthMaterial(网格深度材质)根据摄像机距离进行调色
MeshNormalMaterial(网格法向材质)根据法向量计算物体颜色
MeshLambertMaterial(网格Lambert 材质)考虑光照影响的材质,用于创建不光亮的物体
MeshPhongMaterial(网格 Phong式材质)考虑光照影响的材质,用于创建光亮的物体
MeshBasicMaterial(网格基础材质) 可赋予简单颜色它能够计算出表面与光线的正确互动关系,从面便 染出的物体看起来更加真实(新)
MeshPhysicalMaterial(网格物理材质)这是MeshPhongMaterial的扩展材质(新)
MeshToonMaterial(网格卡通材质)MeshPhongMaterial的扩展材质,更卡通化
ShadowMaterial(阴影材质)专门用于接收阴影图的特殊材质。在该材质中只有 阴影图像,非阴影部分为完全透明的区域
ShaderMaterial(着色器材质)这种材质允许使用自定义的着色器程序,直接控制顶点的放置方式及像素的着色方式
LineBasicMaterial(直线基础材质)这种材质可以用于THREE.Line(直线)几何体,用来创建着色的直线
LineDashMaterial(虚线材质)创建出一种虚线的效果
点材质PointsMaterial

点材质比较简单,只有PointsMaterial,通常使用点模型的时候会使用点材质PointsMaterial。

点材质PointsMaterial的.size属性可以每个顶点渲染的方形区域尺寸像素大小。

var geometry = new THREE.SphereGeometry(100, 25, 25); //创建一个球体几何对象

// 创建一个点材质对象
var material = new THREE.PointsMaterial({
  color: 0x0000ff, //颜色
  size: 3, //点渲染尺寸
});
//点模型对象  参数:几何体  点材质
var point = new THREE.Points(geometry, material);
scene.add(point); //网格模型添加到场景中
12345678
线材质

线材质有基础线材质LineBasicMaterial和虚线材质LineDashedMaterial两个,通常使用使用Line等线模型才会用到线材质。

基础线材质LineBasicMaterial。

var geometry = new THREE.SphereGeometry(100, 25, 25);//球体
// 直线基础材质对象
var material = new THREE.LineBasicMaterial({
  color: 0x0000ff
});
var line = new THREE.Line(geometry, material); //线模型对象
scene.add(line); //点模型添加到场景中
1234567
虚线材质LineDashedMaterial
// 虚线材质对象:产生虚线效果
var material = new THREE.LineDashedMaterial({
  color: 0x0000ff,
  dashSize: 10,//显示线段的大小。默认为3。
  gapSize: 5,//间隙的大小。默认为1
});
var line = new THREE.Line(geometry, material); //线模型对象
//  computeLineDistances方法  计算LineDashedMaterial所需的距离数组
line.computeLineDistances();
123456789
网格模型

Threejs提供的网格类材质比较多,网格材质涉及的材质种类和材质属性也比较多

网格材质顾名思义,网格类模型才会使用的材质对象。

基础网格材质对象MeshBasicMaterial,不受带有方向光源影响,没有棱角感。

var material = new THREE.MeshBasicMaterial({
  color: 0x0000ff,
})
MeshLambertMaterial材质可以实现网格Mesh表面与光源的漫反射光照计算,有了光照计算,物体表面分界的位置才会产生棱角感。

var material = new THREE.MeshLambertMaterial({
  color: 0x00ff00,
});
12345678

高光网格材质MeshPhongMaterial除了和MeshLambertMaterial一样可以实现光源和网格表面的漫反射光照计算,还可以产生高光效果(镜面反射)。

var material = new THREE.MeshPhongMaterial({
  color: 0xff0000,
  specular:0x444444,//高光部分的颜色
  shininess:20,//高光部分的亮度,默认30
});
12345

材质和模型对象对应关系
使用材质的时候,要注意材质和模型的对应关系

常见材质比较:

//light
scene.add(new THREE.AmbientLight(0xffffff, 0.2))
const light = new THREE.DirectionalLight(0xffffff)
light.position.set(2, 2, 2)
scene.add(light)
gui.add(light.position, 'x', -5, 5).name('灯光位置X')
gui.add(light.position, 'y', -5, 5).name('灯光位置Y')
gui.add(light.position, 'z', -5, 5).name('灯光位置Z')
//geometry
const geometry = new THREE.SphereGeometry(0.5)
//material

// MeshBasicMaterial
// const material = new THREE.MeshBasicMaterial()
// // material.wireframe = true
// material.visible = true
// material.color = new THREE.Color(0xff0000)
// // material.color.set(0xff0000)

//MeshNormalMaterial
// const material = new THREE.MeshNormalMaterial()

//MeshLambertMaterial
const material = new THREE.MeshLambertMaterial({
    color: 0xff00ff,
})

//MeshPhongMaterial
const material2 = new THREE.MeshPhongMaterial({
    color: 0xff00ff,
    shininess: 50   //闪亮程度,高光
})

//MeshStandardMaterial
const material3 = new THREE.MeshStandardMaterial({
    color: 0xff00ff,
    roughness: 0,   //粗糙成都
    metalness: 0.2,  //金属性
})
gui.add(material3, 'roughness', 0, 1, 0.01)
gui.add(material3, 'metalness', 0, 1, 0.01

10.灯光(Light)介绍

见官网详细AmbientLight – three.js docs (threejs.org) 所有基本Light的基本属性

环境光AmbientLight

环境光是没有特定方向的光源,主要是均匀整体改变Threejs物体表面的明暗效果,这一点和具有方向的光源不同,比如点光源可以让物体表面不同区域明暗程度不同

//环境光:环境光颜色RGB成分分别和物体材质颜色RGB成分分别相乘
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);//环境光对象添加到scene场景中

你可以把光源颜色从0x444444更改为0x888888,可以看到threejs场景中的网格模型表面变的更亮。

点光源PointLight

点光源就像生活中的白炽灯,光线沿着发光核心向外发散,同一平面的不同位置与点光源光线入射角是不同的,点光源照射下,同一个平面不同区域是呈现出不同的明暗效果。

和环境光不同,环境光不需要设置光源位置,而点光源需要设置位置属性.position,光源位置不同,物体表面被照亮的面不同,远近不同因为衰减明暗程度不同。

你可以把案例源码中点光源位置从(400, 200, 300)位置改变到(-400, -200, -300),你会发现网格模型被照亮的位置从前面变到了后面,这很正常,光源只能照亮面对着光源的面,背对着光源的无法照射到,颜色会比较暗。

//点光源
var point = new THREE.PointLight(0xffffff);
//设置点光源位置,改变光源的位置
point.position.set(400, 200, 300);
scene.add(point);
平行光DirectionalLight

平行光顾名思义光线平行,对于一个平面而言,平面不同区域接收到平行光的入射角一样。

点光源因为是向四周发散,所以设置好位置属性.position就可以确定光线和物体表面的夹角,对于平行光而言,主要是确定光线的方向,光线方向设定好了,光线的与物体表面入射角就确定了,仅仅设置光线位置是不起作用的。

在三维空间中为了确定一条直线的方向只需要确定直线上两个点的坐标即可,所以Threejs平行光提供了位置.position和目标.target两个属性来一起确定平行光方向。目标.target的属性值可以是Threejs场景中任何一个三维模型对象,比如一个网格模型Mesh,这样Threejs计算平行光照射方向的时候,会通过自身位置属性.position和.target表示的物体的位置属性.position计算出来。

// 平行光
var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(80, 100, 50);
// 方向光指向对象网格模型mesh2,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh2;
scene.add(directionalLight);

平行光如果不设置.position和.target属性,光线默认从上往下照射,也就是可以认为(0,1,0)和(0,0,0)两个坐标确定的光线方向。

聚光源SpotLight

聚光源可以认为是一个沿着特定方会逐渐发散的光源,照射范围在三维空间中构成一个圆锥体。通过属性.angle可以设置聚光源发散角度,聚光源照射方向设置和平行光光源一样是通过位置.position和目标.target两个属性来实现。

// 聚光光源
var spotLight = new THREE.SpotLight(0xffffff);
// 设置聚光光源位置
spotLight.position.set(200, 200, 200);
// 聚光灯光源指向网格模型mesh2
spotLight.target = mesh2;
// 设置聚光光源发散角度
spotLight.angle = Math.PI / 6
scene.add(spotLight);//光对象添加到scene场景中

光源辅助对象

Threejs提供了一些光源辅助对象,就像AxesHelper可视化显示三维坐标轴一样显示光源对象,通过这些辅助对象可以方便调试代码,查看位置、方向。

辅助对象 构造函数名
聚光源辅助对象 SpotLightHelper
点光源辅助对象 PointLightHelper
平行光光源辅助对象 DirectionalLightHelper

光照计算算法

Three.js渲染的时候光照计算还是比较复杂的,这里不进行深入介绍,只给大家说下光源颜色和网格模型Mesh颜色相乘的知识,如果你有兴趣可以学习计算机图形学或者WebGL教程。

Threejs在渲染的时候网格模型材质的颜色值mesh.material.color和光源的颜色值light.color会进行相乘,简单说就是RGB三个分量分别相乘。

平行光漫反射简单数学模型:漫反射光的颜色 = 网格模型材质颜色值 x 光线颜色 x 光线入射角余弦值

漫反射数学模型RGB分量表示:(R2,G2,B2) = (R1,G1,B1) x (R0,G0,B0) x cosθ

R2 = R1 * R0 * cosθ
G2 = G1 * G0 * cosθ
B2 = B1 * B0 * cosθ
颜色相乘测试

你可以通过下面代码验证上面颜色相乘的算法,比如把网格模型的颜色设置为白色0xffffff,也就意味着可以反射任意光照颜色,然后把环境光和点光源只保留红色成分,绿色和蓝色成分都设置为0。你可以看到网格模型会把渲染为红色。

// 网格模型材质设置为白色
var geometry = new THREE.BoxGeometry(100, 100, 100); //
var material = new THREE.MeshLambertMaterial({
  color: 0xffffff
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

//环境光   环境光颜色RGB成分分别和物体材质颜色RGB成分分别相乘
var ambient = new THREE.AmbientLight(0x440000);
scene.add(ambient);//环境光对象添加到scene场景中
//点光源
var point = new THREE.PointLight(0xff0000);
//设置点光源位置  光源对象和模型对象的position属性一样是Vector3对象
//PointLight的基类是Light  Light的基类是Object3D  点光源对象继承Object3D对象的位置属性position
point.position.set(400, 200, 300);
scene.add(point);

你还可以尝试把网格模型设置为纯蓝色0x0000ff,光源颜色只保留红色成分不变,你可以看到网格模型的渲染效果是黑色,因为这两个颜色相乘总有一个RGB分量为0,相乘的结果是0x00000,也就是黑色。这也符合实际的物理规律,蓝色的物体不会反射红色的光线,熙然就是黑色效果。

如果你想模拟一个舞台的各种颜色灯光效果,可以用这种思路设置RGB各个分量值来实现特定颜色光源,不过一般渲染的时候RGB三个分量是相同的,也就是表示白色光源,0xffffff表示最高强度的白色光源,0x000000相当于没有光照。

各种Light详解
import * as THREE from 'three'
import Stat from 'three/examples/jsm/libs/stats.module'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import * as dat from 'dat.gui'
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper'

const w = window.innerWidth
const h = window.innerHeight
const stat = new Stat()
const gui = new dat.GUI()

//Scene
const scene = new THREE.Scene()

//Plane 
const planeM = new THREE.MeshPhongMaterial({ color: 0xcccccc })
const planeG = new THREE.PlaneGeometry(4, 4)
const plane = new THREE.Mesh(planeG, planeM)
plane.rotation.x = -0.5 * Math.PI
scene.add(plane)

//Material 
const material = new THREE.MeshStandardMaterial({ color: 0xff00ff })

//Sphere
const sphereG = new THREE.SphereGeometry(0.5)
const sphere = new THREE.Mesh(sphereG, material)
sphere.position.y = 0.5
scene.add(sphere)

//Cube
const cubeG = new THREE.BoxGeometry(0.5, 0.5, 0.5)
const cube = new THREE.Mesh(cubeG, material)
cube.position.set(1, 0.8, 0)
scene.add(cube)

//Torus
const torusG = new THREE.TorusGeometry(0.3, 0.1, 10, 20)
const torus = new THREE.Mesh(torusG, material)
torus.position.set(-1, 0.8, 0)
torus.rotation.x = -0.5 * Math.PI
scene.add(torus)

const colors = {
    dLight: 0xffffff,
    sLight: 0xffffff,
    pLight: 0xffffff,
}

//light
//AmbientLight 环境光
const aLight = new THREE.AmbientLight(0xffffff, 0.2)
// aLight.intensity = 0.2
scene.add(aLight)

//DirectionalLight
const dLight = new THREE.DirectionalLight(0xffffff)
// dLight.intensity = 1
dLight.position.set(1, 1, 1)
// scene.add(dLight)
const dFol = gui.addFolder('DirectionalLight')
dFol.addColor(colors, 'dLight').onChange(() => {
    dLight.color.set(colors.dLight)
})
dFol.add(dLight, 'intensity', 0, 1, 0.01)
dFol.add(dLight.position, 'x', -5, 5)
dFol.add(dLight.position, 'y', -5, 5)
dFol.add(dLight.position, 'z', -5, 5)

const dLightHelper = new THREE.DirectionalLightHelper(dLight)
// scene.add(dLightHelper)

//SpotLight
const spotLight = new THREE.SpotLight(0xffffff)
spotLight.position.set(1, 1, 1)
spotLight.angle = 60 / 180 * Math.PI
// spotLight.distance = 2
// scene.add(spotLight)

const sFol = gui.addFolder('spotLight')
sFol.addColor(colors, 'sLight').onChange(() => {
    spotLight.color.set(colors.sLight)
})
sFol.add(spotLight, 'intensity', 0, 1, 0.01)
sFol.add(spotLight.position, 'x', -5, 5)
sFol.add(spotLight.position, 'y', -5, 5)
sFol.add(spotLight.position, 'z', -5, 5)
sFol.add(spotLight, 'distance', 0.1, 10)
sFol.add(spotLight, 'angle', 0.01, 3.14)

const spotLightHelper = new THREE.SpotLightHelper(spotLight)
// scene.add(spotLightHelper)

//PointLight
const pointLight = new THREE.PointLight(0xffffff)
pointLight.position.y = 2
pointLight.intensity = 1
pointLight.distance = 2
// scene.add(pointLight)

const PFol = gui.addFolder('pointLight')
PFol.addColor(colors, 'pLight').onChange(() => {
    pointLight.color.set(colors.pLight)
})
PFol.add(pointLight, 'intensity', 0, 1, 0.01)
PFol.add(pointLight.position, 'x', -5, 5)
PFol.add(pointLight.position, 'y', -5, 5)
PFol.add(pointLight.position, 'z', -5, 5)
PFol.add(pointLight, 'distance', 0.1, 10)
   
const pointLightHelper = new THREE.PointLightHelper(pointLight)
// scene.add(pointLightHelper)

//RectAreaLight - MeshStanardMaterial / MeshPhysicalMaterial
const rectAreaLight = new THREE.RectAreaLight(0xffffff, 1, 1, 1)
rectAreaLight.position.set(0, 1, 0)
rectAreaLight.rotation.x = -0.5 * Math.PI
// scene.add(rectAreaLight)

const helper = new RectAreaLightHelper(rectAreaLight)
// scene.add(helper)

//HemisphereLight  -skyColor, -backgroundColor
const hLight = new THREE.HemisphereLight(0xff0000, 0x0000ff)
scene.add(hLight)

//Camera 
const camera = new THREE.PerspectiveCamera(75, w / h, 0.1, 10)
camera.lookAt(0, 0, 0)
camera.position.set(0, 2, 3)

//Renderer
const renderer = new THREE.WebGLRenderer()
renderer.setSize(w, h)
document.body.append(renderer.domElement)
document.body.append(stat.dom)
const orbitControls = new OrbitControls(camera, renderer.domElement)
const clock = new THREE.Clock()
tick()
function tick() {
    const time = clock.getElapsedTime()

    cube.rotation.x = time * 0.4
    cube.rotation.y = time * 0.4
    torus.rotation.y = time * 0.4
    torus.rotation.y = time * 0.4

    requestAnimationFrame(tick)
    renderer.render(scene, camera)
    stat.update()
    orbitControls.update()
    // spotLightHelper.update()
}

11.阴影shadow

Three.js产生阴影的原理

threejs产生阴影的计算方式是以光源的脚步出发,射向被照射的物体,然后以光源的角度正向看着物体,被物体遮盖的地方就是阴影,然后在接收阴影的物体(地面)上显示。

设置阴影的步骤
1.renderer设置

首先我们需要告诉渲染器我们需要阴影效果:

renderer.shadowMap.enabled = true;

更多详细内容可以查看WebGLRenderer的shadowMap属性。

2.光源设置

然后我们需要定义能够产生阴影的光源:

light.castShadow = true;

注意: 不是所有的光源都能够产生阴影,只有一部分光源可以,例如通过THREE.PointLight(点光源)、THREE.SpotLight(聚光源)和THREE.DirectionalLight(平行光光源)定义的光源是能够产生阴影的。

3.指定物体投射阴影

接下来我们需要指定场景中的哪些物体能够投射阴影,能够产生阴影的物体需要设置以下代码:

const geometry = new THREE.BoxBufferGeometry(4, 4, 4); // 生成几何体
const material = new THREE.MeshLambertMaterial({ // 生成材质
    color: 0x00ff00,
});
const mesh = new THREE.Mesh(geometry, material); // 生成网格
mesh.castShadow = true; // 对象是否渲染到阴影贴图中,默认值为false

注意: 只有castShadow属性为true的物体才会产生阴影。

4.指定物体接受阴影

最后我们还需要指定哪些物体能够接受阴影,这样才能够看出阴影效果。

const planeGeometry = new THREE.PlaneGeometry(300, 300); // 生成平面几何
const planeMaterial = new THREE.MeshLambertMaterial({ // 生成材质
  color: 0xcccccc,
});
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); // 生成平面网格
planeMesh.receiveShadow = true; // 设置平面网格为接受阴影的投影面
5.调整阴影分辨率
//设置阴影分辨率
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
scene.add(spotLight);

此时,阴影就显得比较逼真了。

其他

1、阴影类型:
THREE.BasicShadowMap = 0; //默认
THREE.PCFShadowMap = 1; //渐淡
THREE.PCFSoftShadowMap = 2; //渐淡柔化
2、mesh.castShadow = true; mesh.receiveShadow = true;
可以得出要使网格接受阴影,需要开启reciveShadow;要使网格在光照下产生阴影,需要开启castShadow
3、spotLight.shadowCameraVisible=true; shadowCameraVisible只有在老版本的threejs库中才支持,新版本已废除。
4、在创建 THREE.AmbientLight 时,颜色会应用到全局。该光源并没有特别的来源方向,并且 THREE.AmbientLight 不会产生阴影。
5、通常,不能将 THREE.AmbientLight 作为场景中唯一的光源,因为它会将场景中的所有物体渲染为相同的颜色,而不管是什么形状。在使用其他光源(如 THREE.SpotLight 或者 THREE.DirectionLight)的同时使用它,目的是弱化阴影或给场景添加一些额外的颜色。

12.相机(camera_batch)

1.正射(正交)投影相机OrthographicCamera(left, right, top, bottom, near, far)
var camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);

构造器(Constructor)
OrthographicCamera( left, right, top, bottom, near, far )
left — 相机视椎体(Camera frustum)左面。
right — 相机视椎体(Camera frustum)右面。
top — 相机视椎体(Camera frustum)上面。
bottom — 相机视椎体(Camera frustum)下面。
near — 相机视椎体(Camera frustum)前面(靠近相机的这一面)。
far — 相机视椎体(Camera frustum)后面(远离相机的这一面)。

2.透视投影相机 PerspectiveCamera( fov, aspect, near, far )

fov: 视角,表示能看到的视角范围,视角大小设置要根据具体应用,一般游戏设置60-90度。

aspect 渲染窗口的长宽比,near表示距离相机多远的位置开始渲染;far 表示距离相机多远的位置停止渲染

var width = window.innerWidth;
var height = window.innerHeight;
var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
this.camera.position.set(-10000, 12000, -12000) // 设置相机位置
this.camera.lookAt(new THREE.Vector3(0, 0, 0)) // 设置相机方向
this.camera.zoom=0.5  //视野的缩放

13.窗口resize与事件监听

window.addEventListener()监听函数,用来实现窗口的大小变化时,渲染的模型也随之变化,也可以用来实现控制器。(非常常用)

//resize
window.addEventListener('resize', () => {
    w = window.innerWidth
    h = window.innerHeight

    //Camera
    camera.aspect = w / h
    camera.updateProjectionMatrix()

    //Renderer
    renderer.setSize(w, h)
})
//mousemove
// window.addEventListener('mousemove', (e) => {
//   const mousePosX = (e.clientX / w - 0.5) * 2
//   const mousePosY = (e.clientY / h - 0.5) * 2
//   camera.position.x = -mousePosX
//   camera.position.y = mousePosY
// })

14.贴图Texture

基本使用
//贴图 texture
const loader = new THREE.TextureLoader()
const texture = loader.load('https://threejs.org/manual/examples/resources/images/wall.jpg')
const texture2 = loader.load('https://threejs.org/manual/resources/images/compressed-but-large-wood-texture.jpg')
const texture3 = loader.load(t1)
const m1 = new THREE.MeshStandardMaterial({
    map: loader.load('https://threejs.org/manual/examples/resources/images/flower-1.jpg')
})
const m2 = new THREE.MeshStandardMaterial({
    map: loader.load('https://threejs.org/manual/examples/resources/images/flower-2.jpg')
})
const m3 = new THREE.MeshStandardMaterial({
    map: loader.load('https://threejs.org/manual/examples/resources/images/flower-3.jpg')
})
const m4 = new THREE.MeshStandardMaterial({
    map: loader.load('https://threejs.org/manual/examples/resources/images/flower-4.jpg')
})
const m5 = new THREE.MeshStandardMaterial({
    map: loader.load('https://threejs.org/manual/examples/resources/images/flower-5.jpg')
})
const m6 = new THREE.MeshStandardMaterial({
    map: loader.load('https://threejs.org/manual/examples/resources/images/flower-6.jpg')
})
//Cube
const cubeG = new THREE.BoxGeometry(1, 1, 1)
const cubeM = new THREE.MeshStandardMaterial({
    // color: 0xff0000,
    map: texture3,
})
const cube = new THREE.Mesh(cubeG, [m1, m2, m3, m4, m5, m6])
cube.castShadow = true
cube.position.y = 0.5
scene.add(cube)
//Plane
const planeGeometry = new THREE.PlaneGeometry(4, 4)
const planeMaterial = new THREE.MeshStandardMaterial({
    // color: 0xff0000,
    map: texture2,
    side: THREE.DoubleSide,
})
const plane = new THREE.Mesh(planeGeometry, planeMaterial)
plane.rotation.x = -0.5 * Math.PI
plane.receiveShadow = true
scene.add(plane)
属性
名称描述
id此纹理实例的唯一编号。
uuid此对象实例的UUID。这会自动分配,所以不应该编辑。
name对象的名称,可以重复,默认值为空字符串
image一个Image对象,通常使用 ImageUtils 或 ImageLoader 类来创建。Image对象可以包括图像 (比如 PNG, JPG, GIF, DDS), 视频 (e.g., MP4, OGG/OGV), 或者六幅图像的集合用于一个立方体贴图。 要使用视频作为一个纹理,你需要把一个HTML5视频元素作为纹理图像的源,并在视频播放时不断更新这个纹理-VideoTexture类会自动处理。
mipmap用户指定的mipmap数组(可选)
mapping如何将图像应用到对象。默认为 UV贴图(THREE.UVMapping)类型,这里U,V 坐标用来应用映射,要求是单个纹理。其他类型包括:THREE.CubeReflectionMapping:立方体反射映射THREE.CubeRefractionMapping:立方体折射映射THREE.EquirectangularReflectionMapping:圆柱反射映射THREE.EquirectangularRefractionMapping:圆柱折射映射THREE.SphericalReflectionMapping:球面反射映射
wrapS缺省为 THREE.ClampToEdgeWrapping, 表示边缘被夹到纹理单元(texels)的外边界。THREE.ClampToEdgeWrapping:夹边。超过1.0的值被固定为1.0。超过1.0的其它地方的纹理,沿用最后像素的纹理。用于当叠加过滤时,需要从0.0到1.0精确覆盖且没有模糊边界的纹理。其他两个选项是:THREE.RepeatWrapping:平铺重复。超过1.0的值都被置为0.0。纹理被重复一次。在渲染具有诸如砖墙之类纹理的物体时,如果使用包含一整张砖墙的纹理贴图会占用较多的内存,通常只需载入一张具有一块或多块砖瓦的较小的纹理贴图,再把它按照重叠纹理寻址模式在物体表面映射多次,就可以达到和使用整张砖墙贴图同样的效果。THREE.MirroredRepeatWrapping:镜像重复。每到边界处纹理翻转,意思就是每个1.0 u或者v处纹理被镜像翻转
wrapT缺省为 THREE.ClampToEdgeWrapping, 表示边缘被夹到纹理单元(texels)的外边界。其他两个选项是 THREE.RepeatWrapping 和 THREE.MirroredRepeatWrapping。注意: 平铺图像纹理仅在图像尺寸是2的幂次方(2,4,8,16,32,64,128,256,512,1024,2048,…)时工作。每个维度的值不一定是相同的,但每一个维度都必须是2的幂次方。这是WebGL的限制,不是Three.js的。
magFilter该属性定义当一个纹理单元(texel)覆盖多个像素点时纹理如何采样。缺省为 THREE.LinearFilter,表示获取4个最近的纹理单元执行双向线性插值计算(显示效果好)。另外的选项是 THREE.NearestFilter, 表示使用最近的texel(性能优)。
minFilter该属性定义当一个纹理单元(texel)不足以覆盖单个像素点时纹理如何采样。缺省为 THREE.LinearMipMapLinearFilter, 表示使用多级纹理贴图(mipmapping)以及一个三线性滤波器。其他选项是:THREE.NearestFilter:最近滤镜。在纹理基层上执行最邻近过滤。THREE.NearestMipMapNearestFilter:选择最临近的mip层,并执行最临近的过滤。THREE.NearestMipMapLinearFilter:在mip层之间执行线性插补,并执行最临近的过滤。THREE.LinearFilter:在纹理基层上执行线性过滤。THREE.LinearMipMapNearestFilter:选择最临近的mip层,并执行线性过滤。THREE.LinearMipMapLinearFilter:在mip层之间执行线性插补,并执行线性过滤。
anisotropy表示纹理的各向异性。沿纹理单元密度最高方向的轴线所取样本数。默认情况下,这个值为1。较高的值比基础MipMap要更清晰,但需要更多的采样。 使用renderer.getMaxAnisotropy()方法来找到GPU最大有效各向异性值;这个值通常是2的幂次方。
format缺省纹理格式为THREE.RGBAFormat。其他格式有:THREE.AlphaFormat:对应于GL_ALPHA。Alpha 值THREE.RGBFormat:Red, Green, Blue 三原色值THREE.RGBAFormat:Red, Green, Blue 和 Alpha 值THREE.LuminanceFormat:灰度值THREE.LuminanceAlphaFormat:灰度值和 Alpha 值THREE.RGBEFormat
type缺省纹理格式为THREE.RGBAFormat。其他格式有:THREE.UnsignedByteType:无符号8位整形值(1个字节)THREE.ByteType:带符号8位整形值(1个字节)THREE.ShortType:带符号16位整形值(2个字节)THREE.UnsignedShortType:无符号16未整形值(2个字节)THREE.IntType:带符号32位整形值(4个字节)THREE.UnsignedIntType:无符号32位整形值(4个字节)THREE.FloatType:单精度浮点型(4个字节)THREE.HalfFloatType:半浮点型
offset在U和V方向上,纹理在模型表面上重复绘制时的偏移。通常范围是0.0 到 1.0。注意: offset属性是一个便捷修饰符,仅影响Texture对模型上第一组UV的应用。如果纹理用作需要额外UV集的贴图(例如,大多数库存材料的aoMap或lightMap),则必须手动分配这些UV以获得所需的偏移量
repeat纹理在整个表面上重复多少次,在每个方向U和V上。如果在任一方向上repeat设置为大于1,则相应的Wrap参数也应设置为 THREE.RepeatWrapping或THREE.MirroredRepeatWrapping以实现所需的平铺影响。注意: repeat属性是一个便捷修饰符,仅影响Texture对模型上第一组UV的应用。如果纹理用作需要额外UV集的贴图(例如,大多数库存材料的aoMap或lightMap),则必须手动分配这些UV以实现所需的重复。
rotation纹理围绕中心点旋转多少,以弧度表示。正值是逆时针的。缺省值是0。
center旋转发生的点。值(0.5,0.5)对应于纹理的中心。默认值是(0,0),左下角。matrixAutoUpdate 是否更新纹理的UV-变换.matrix从纹理特性.offset,.repeat, .rotation和.center。默认情况下为真。如果直接指定uv-transform矩阵,则将其设置为false。
matrix纹理的uv转换矩阵。从质地特性渲染更新.offset,.repeat, .rotation和.center当纹理的.matrixAutoUpdate属性为true。当.matrixAutoUpdate属性为false时,可以手动设置此矩阵。默认值是单位矩阵
generateMipmaps是否为纹理生成mipmap(如果可能)。默认情况下为真。如果您手动创建mipmap,请将其设置为false。
premultiplyAlpha在默认情况下,这是PNG图像的标准。如果RGB值已被预乘alpha,则设置为true。
flipY默认为真。翻转图像的Y轴以匹配WebGL纹理坐标空间。
unpackAlignment默认值为4。指定内容中每个像素行起点的对齐要求。有效值有 1 (字节对齐byte-alignment), 2 (行起点按偶数字节对齐), 4 (字对齐word-alignment), 和 8(行起点按双字对齐)。参阅:glPixelStorei 以了解更多信息。
encoding编码方式。默认设置为 THREE.LinearEncoding,但是支持 sRGB, RGBE, RGBM, RGBD, LogLuv 和 Gamma。 重要:如果纹理中的这个值在材料已用后被改变,则需要触发一个Material.needsUpdate操作,以便该值在着色器中得到实现。
version从0开始计算needsUpdate更新次数
onUpdate/needsUpdate一个回调函数,当纹理被更新时调用(例如,当needsUpdate被设置为true并且纹理被使用时)。needsUpdate将其设置为true以在下次使用纹理时触发更新。对于设置换行模式尤为重要。
方法
名称描述
.updateMatrix ()更新纹理的UV-变换.matrix从纹理特性.offset,.repeat, .rotation和.center。
.clone( texture : Texture )制作纹理的副本。请注意,这不是“深层复制”,图像是共享的。
.toJSON( meta )meta - 包含元数据的可选对象。将材质转换为three.js JSON格式。
.dispose ()使用一个’dispose’事件类型来调用 EventDispatcher.dispatchEvent 方法(自定义事件类)。
.transformUv ( uv )根据此纹理的.offset,.repeat, .wrapS,.wrapT和.flipY属性的值转换uv 。

15.线line

原理说明:
Three.js中渲染线条提供了三个API,分别是gl.LINE_STRIP,gl.LINES,gl.LINE_LOOP。gl.LINE_STRIP用于渲染一系列的点,会从第一个点开始到最后一个点依次连接起来;gl.LINES用于渲染两两组合的点,它会将我们传递的一系列点自动分配成两个点为一组,然后将分成的每个组中的两个点连接;gl.LINE_LOOP用于渲染一系列的点,但是这个API和gl.LINE_STRIP最大的不同是所有点渲染完之后会将第一个点和最后一个点连接,达到闭合状态。

Line用于将一系列点绘制成一条连续的线,Three.js渲染Line使用的是gl.LINE_STRIP,Line会将我们存储在Geometry的点依次连接起来形成线条,这种线条在实际项目中一般用于绘制迁徙轨迹或者绘制已知点的线条。创建一个Line的代码如下:

var geometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
    color: '#ff0000'
    lineWidth:20  //线宽
});
geometry.vertices.push(
    new THREE.Vector3(20,20,0),
    new THREE.Vector3(20,-20,0),
    new THREE.Vector3(-20,-20,0),
    new THREE.Vector3(-20,20,0)
)

var line = new THREE.Line(geometry, lineMaterial);
scene.add(line);EE.LineLoop(geometry, lineMaterial);
scene.add(line);

LineLoop用于将一系列点绘制成一条连续的线,它和Line几乎一样,唯一的区别就是所有点连接之后会将第一个点和最后一个点相连接,这种线条在实际项目中用于绘制某个区域,比如在地图上用线条勾选出某一区域。Three.js渲染LineLoop使用的是gl.LINE_LOOP。创建一个LineLoop的代码如下:

var geometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
    color: '#ff0000'
    lineWidth:20  //线宽
});
geometry.vertices.push(
    new THREE.Vector3(20,20,0),
    new THREE.Vector3(20,-20,0),
    new THREE.Vector3(-20,-20,0),
    new THREE.Vector3(-20,20,0)
)
 
var line = new THREE.LineLoop(geometry, lineMaterial);
scene.add(line);

LineSegments用于将两个点连接为一条线,它会将我们传递的一系列点自动分配成两个为一组,然后将分配好的两个点连接,这种先天实际项目中主要用于绘制具有相同开始点,结束点不同的线条,比如常用到的遗传图。Three.js渲染LineSegments使用的是gl.LINES。创建一个LineSegments的代码如下:

var geometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
    color: '#ff0000'
    lineWidth:20  //线宽
});
geometry.vertices.push(
    new THREE.Vector3(20,20,0),
    new THREE.Vector3(20,-20,0),
    new THREE.Vector3(-20,-20,0),
    new THREE.Vector3(-20,20,0)
)

var line = new THREE.LineSegments(geometry, lineMaterial);
scene.add(line);

ector3(20,20,0),
new THREE.Vector3(20,-20,0),
new THREE.Vector3(-20,-20,0),
new THREE.Vector3(-20,20,0)
)

var line = new THREE.Line(geometry, lineMaterial);
scene.add(line);EE.LineLoop(geometry, lineMaterial);
scene.add(line);


LineLoop用于将一系列点绘制成一条连续的线,它和Line几乎一样,唯一的区别就是所有点连接之后会将第一个点和最后一个点相连接,这种线条在实际项目中用于绘制某个区域,比如在地图上用线条勾选出某一区域。Three.js渲染LineLoop使用的是gl.LINE_LOOP。创建一个LineLoop的代码如下:

```js
var geometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
    color: '#ff0000'
    lineWidth:20  //线宽
});
geometry.vertices.push(
    new THREE.Vector3(20,20,0),
    new THREE.Vector3(20,-20,0),
    new THREE.Vector3(-20,-20,0),
    new THREE.Vector3(-20,20,0)
)
 
var line = new THREE.LineLoop(geometry, lineMaterial);
scene.add(line);

LineSegments用于将两个点连接为一条线,它会将我们传递的一系列点自动分配成两个为一组,然后将分配好的两个点连接,这种先天实际项目中主要用于绘制具有相同开始点,结束点不同的线条,比如常用到的遗传图。Three.js渲染LineSegments使用的是gl.LINES。创建一个LineSegments的代码如下:

var geometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
    color: '#ff0000'
    lineWidth:20  //线宽
});
geometry.vertices.push(
    new THREE.Vector3(20,20,0),
    new THREE.Vector3(20,-20,0),
    new THREE.Vector3(-20,-20,0),
    new THREE.Vector3(-20,20,0)
)

var line = new THREE.LineSegments(geometry, lineMaterial);
scene.add(line);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

特嗷涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值