threejs的初步认识和学习记录

THREE 学习记录

这里项目搭建的打包工具使用的不是 webpack 也不是 vite 更不是 gulp ,而是 parcel 一个极速零配置 web 应用打包工具。

首先需要全局安装这个工具

$ npm install -g parcel-bundler

搭建项目环境

新建一个项目文件夹,然后初始化项目目录

两种初始化项目的方式,一种是开发依赖安装 parcel-bundler,一种是开发依赖安装 parcel

$ npm init -y
$ npm install parcel-bundler -D
$ npm install three

然后修改 package.json 文件的脚本

{
    "scripts": {
        "dev": "parcel src/index.html",
        "build": "parcel build src/index.html"
    }
}

然后再根目录新建若干文件:

- node_modules
- src
    - assets
        - css
            - style.css
        - images
    - main
        - main.js
    - index.html
- package.json

然后在 index.html 文件中写入:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./assets/css/style.css">
    <title>Three</title>
</head>
<body>
    
</body>
<script src="./main/main.js"></script>
</html>

然后运行 npm run dev 这个时候项目回启动一个本地服务:http://localhost:1234/ 并且在根目录会生成一个 dist 文件夹——打包后的文件。

然后安装 gsapdat.gui

$ npm install gsap dat.gui

开始一个简单的3D效果

制作一个简单的3D动画效果,需要5部分组成

  • 场景,类似于 canvas 画布
  • 相机,类似于人的视角
  • 几何物体,三维空间的物体
  • 控制器,三维空间物体的控制
  • 渲染器,顾名思义让3D动画在视图中显示的工具

声明一个场景对象

// main/maim.js
import * as THREE from 'three'
const scene = new THREE.Scene()

声明一个相机

/**
 * 参数1:相机的可视区域夹角度数
 * 参数2:相机的宽高比
 * 参数3:相机的近景距离
 * 参数4:相机的远景距离
 */
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000)

// 把相机添加到场景当中
scene.add(camera)

声明一个几何体

// 创建一个几何体
const cubeGeometry = new THREE.BoxGeometry()

// 设置几何体的材质(基础网格材质)
const cubMaterial = new THREE.MeshBasicMaterial({ color: 0xffff000 })

// 根据几何体和材质创建一个物体
const cube = new THREE.Mesh(cubeGeometry, cubMaterial)

// 将几何体添加到场景中
scene.add(cube)

声明一个控制器

// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)

controls.update()
设置阻尼器
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)

// 设置阻尼器,让控制器更有真实效果,但是必须要在动画循环中调用 update()
controls.enableDamping = true

function animation () {

    controls.update()

    // 进入下一帧的时候触发
    requestAnimationFrame(animation)

    renderer.render(scene, camera)
}

声明一个渲染器

// 初始化渲染器
const renderer = new THREE.WebGLRenderer()

// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)

// 将渲染的canvas内容添加到body中
document.body.appendChild(renderer.domElement)

// 使用渲染器将相机和场景渲染进来
renderer.render(scene, camera)

让物体动起来

修改几何体的位置

// 修改几何物体的位置,两种方法,一中调用方法,一种修改属性值
cube.position.set(5, 0, 0)
cube.position.x = 5

让物体沿着X轴水平移动

function animation () {

    cube.position.x += 0.05
    if (cube.position.x === 5) {
        // 物体位置回到原点
        cube.position.x = 0
    }

    // 进入下一帧的时候触发
    requestAnimationFrame(animation)

    renderer.render(scene, camera)
}

使用补间动画工具来处理动画(Gasp)

import gsap from 'gsap'

// 设置动画
var animation_1 = gsap.to(cube.position, { 
    x: 5, // 沿着X轴移动的距离
    duration: 5, // 动画持续时间
    ease: 'power1.inOut', // 动画撒贝尔曲线
    repeat: 2, // 动画重复次数,值为-1时为无限循环
    yoyo: true, // 往返的运动
    delay: 2, // 延迟时间
    onStart: () => {
        console.log('动画开始')
    },
    onComplete: () => {
        console.log('动画完成')
    }
})
// 双击让动画停下来
window.addEventListener('dblclick', () => {
    // 判断动画是否是激活状态
    if (animation_1.isActive()) {
        // 暂停动画
        animation_1.pause()
    } else {
        // 恢复动画
        animation_1.resume()
    }
})

通过 Clock 时钟来跟踪时间、处理时间

const clock = new THREE.Clock()

// 获取时钟运行总时长
let dateTime = clock.getDelta()

通过用户操作界面更改物体属性(dat.gui)

import * as dat from 'dat.gui'
const gui = new dat.GUI()

添加物体水平移动的用户可操作项

gui.add(cube.position, 'x')
    .min(0)
    .max(5)
    .step(0.01)
    .name('水平移动')
    .onChange(value => {
        console.log('物体水平移动的距离:' + value)
    })
    .onFinishChange(value => {
        console.log('完成改变时的物体水平移动的距离:' + value)
    })

添加改变物体颜色的用户可操作项

const params = {
    color: '#FFFFFF'
}
gui.addColor(params, 'color').name('改变颜色')
    .onChange(value => {
        console.log('物体改变的颜色是:' + value)
        cube.material.color.set(value)
    })

添加物体是否显示的用户可操作项

gui.add(cube, 'visible').name('是否显示')

将多个用户操作项归纳到一个折叠框中

const folder = gui.addFolder('设置物体的属性')
const params = {
    color: '#ffff00',
    fn: () => {
        gsap.to(cube.position, { x: 5, duration: 2, yoyo: true, repeat: -1 })
    }
}
folder.add(cube.material, 'wireframe')
folder.addColor(params, 'color').name('改变颜色')
folder.add(params, 'fn').name('开启动画')

纹理贴图

在这里插入图片描述

// 导入纹理
const textureLoader = new THREE.TextureLoader()

// 图片的位置在 /dist/texture/bg1.jpg 
const doorColorTexture = textureLoader.load('./texture/bg1.jpg')

// 贴图偏移量设置
doorColorTexture.offset.x = 0.5
doorColorTexture.offset.set(0.5, 0)

// 设置贴图旋转
// 设置贴图的旋转中心
doorColorTexture.center.set(0.5,0.5)
// 设置贴图旋转 45deg
doorColorTexture.rotation = Math.PI / 4

// 设置贴图重复
// 水平重复2次,垂直重复3次
doorColorTexture.repeat.set(2, 3)

// 设置水平方向贴图重复的模式(贴边重复)
doorColorTexture.wrapS = THREE.RepeatWarppering
// 设置垂直方向贴图重复的模式(贴边重复)
doorColorTexture.wrapT = THREE.MirrepeatWarppering

// 设置几何体的材质(基础网格材质)
const cubMaterial = new THREE.MeshBasicMaterial({
    // 这里的 color 颜色会叠加到纹理图上
    // color: 0xffff000,
    map: doorColorTexture
})

在这里插入图片描述

设置透明材质

在这里插入图片描述

// 导入纹理
const textureLoader = new THREE.TextureLoader()

// 图片的位置在 /dist/texture/alpha-bg.jpg
// 图片中黑色区域会被渲染成透明状,白色区域会被渲染成不透明,灰色区域会被渲染成半透明状
const doorColorTexture = textureLoader.load('./texture/alpha-bg.jpg')

// 设置几何体的材质(基础网格材质)
const cubMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true // 设置为 true 透明贴图才会起效
})

在这里插入图片描述

添加平面

// 添加平面
const basicColorTexture = textureLoader.load('./texture/bg4.jpg')

const plane = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(1,1),
    // cubMaterial
    new THREE.MeshBasicMaterial({
        map: basicColorTexture
    })
)

plane.position.set(3, 0, 0)

scene.add(plane)

AO 环境遮挡

在这里插入图片描述

const cubeGeometry = new THREE.BoxBufferGeometry(1,1,1)

// 这是一张白色背景,黑色线条的图,白色在渲染时,会被忽略,黑色线条被作为环境贴图的描边效果,如阴影
const doorAotexture = textureLoader.load('./texture/bg5.jpg')

const cubMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAotexture
})
cubeGeometry.setAttribute(
    'uv2',
    new THREE.BufferAttribute(cubeGeometry.attributes.uv.array, 2)
)

在这里插入图片描述

贴图加载管理

单个贴图加载
const textureLoader = new THREE.TextureLoader()
const doorColorTexture = textureLoader.load('./texture/bg1.jpg')
textureLoader.onLoad = () => {
    console.log('加载完成')
}
贴图加载包管理器批量处理

第一种方式:

const manager = new THREE.LoadingManager()
manager.onStart = function (url, itemsLoaded, itemsTotal) {
    console.log('开始加载文件:', { url, itemsLoaded, itemsTotal })
}
manager.onLoad = function () {
    console.log('加载完成')
}
manager.onProgress = function (url, itemsLoaded, itemsTotal) {
    console.log({ url, itemsLoaded, itemsTotal })
}
manager.onError = function (url) {
    console.error('加载失败')
    console.error(url)
}

第二种方式:

const event = {}
event.onLoad = function () {
    console.log('图片加载完成')
}
event.onProgress = function (url, num, total) {
    console.log('图片加载完成:', url)
    console.log('图片加载进度:', num)
    console.log('图片总数:', total)
    console.log('图片加载进度的百分比:', ((num / total) * 100).toFixed(2) + '%')
}
event.onError = function () {
    console.log('图片加载失败')
}

const manager = new THREE.LoadingManager(
    event.onLoad,
    event.onProgress,
    event.onError
)

// 把包加载管理器传递给贴图加载器,然后每次加载贴图资源的时候都会触发包加载管理器
const textureLoader = new THREE.TextureLoader(manager)

const doorColorTexture = textureLoader.load('./texture/bg1.jpg')

物理光线

环境光线

// 环境光线(从四面八方照射过来的光线)
const light = new THREE.AmbientLight(0xffffff, 0.1)
scene.add(light)

平行光线

// 平行光线(相当于太阳光照射的光线)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)
directionalLight.position.set(0, 10, 10)
scene.add(directionalLight)

在这里插入图片描述

设置置换贴图和贴图厚度

在这里插入图片描述

const cubeGeometry = new THREE.BoxBufferGeometry(1,1,1, 100, 100, 100)

// 导入置换贴图
const doorHeightTexture = textureLoader.load('./texture/bg_5.jpg')

// 设置材质
const cubeMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAotexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture // 置换贴图
    displacementScale: 0.1, // 置换贴图厚度
})

在这里插入图片描述

设置置换贴图粗糙度和光滑度

// 设置材质
const cubeMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAotexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture // 门面贴图
    displacementScale: 0.1, // 门面厚度
    roughness: 0, // 粗糙度
})

在这里插入图片描述

给门上的铆钉设置贴图

在这里插入图片描述

// 加载贴图
const door_6_texture = textureLoader.load('./texture/bg_6.jpg')

// 设置材质
const cubeMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAotexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture // 门面贴图
    displacementScale: 0.1, // 门面厚度
    roughness: 0, // 粗糙度
    roughnessMap: door_6_texture, // 铆钉贴图
})

在这里插入图片描述

设置金属度效果和金属厚度效果

在这里插入图片描述

// 金属贴图
const door_7_texture = textureLoader.load('./texture/bg_7.jpg')

// 设置材质
const cubeMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAotexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture // 门面贴图
    displacementScale: 0.1, // 门面厚度
    roughness: 1, // 粗糙度
    roughnessMap: door_6_texture, // 铆钉贴图
    metalness: 1, // 金属度
    metalnessMap: door_7_texture, // 铆钉金属贴图
})

在这里插入图片描述

设置门面的法线贴图和凹凸效果

在这里插入图片描述

// 导入法线贴图
const door_8_texture = textureLoader.load('./texture/bg_8.jpg')

// 设置材质
const cubeMaterial = new THREE.MeshBasicMaterial({
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAotexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture // 门面贴图
    displacementScale: 0.1, // 门面厚度
    roughness: 1, // 粗糙度
    roughnessMap: door_6_texture, // 铆钉贴图
    metalness: 1, // 金属度
    metalnessMap: door_7_texture, // 铆钉金属贴图
    normalMap: door_8_texture, // 门面法线贴图
})

在这里插入图片描述

环境贴图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值