Three.js语法入门

three.js语法入门

创建一个3D场景

  1. 创建一个虚拟场景用于存放网络模型
/**
 * 创建3D场景对象Scene
 */
const scene = new THREE.Scene();
/**
 * 创建网格模型
 */
//创建一个长方体几何对象Geometry【形状】
const geometry = new THREE.BoxGeometry(50, 50, 50);
//材质对象Material【对象材质】
const material = new THREE.MeshBasicMaterial({
    color: 0x0000ff, //设置材质颜色
});
// 给【网络模型】赋予【形状】和【材质】
// 给网格模型,物体形状和材质外观
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
// 设立【网络模型】的【位置】
mesh.position.set(0,10,0);
// 【添加网络模型到虚拟场景中】
scene.add(mesh); //网格模型添加到场景中 
  1. 创建一个相机用于模拟人眼视角去捕获这一模型

// 2. 创建相机用于拍照,捕获这个场景,模拟人眼观察这个场景
// 定义相机输出的画布大小
const width = 800
const height = 500
// 视锥体
// 参数
// fov:视野,即观察多大范围,观察角度,默认值50
// aspect:一般为canvas的宽高比
// near:四棱台的近的面到相机的距离
// far:四棱台的远的面到相机的距离
// PerspectiveCamera【透视投影相机】
const camera = new THREE.PerspectiveCamera(30,width/height,0.1,3000)

// 给相机位置,x,y,z
camera.position.set(200,200,200)

// 相机的视角,观察哪,也可以使用x,y,z
camera.lookAt(mesh.position)//看向网络模型的位置

image.png
透视投影相机的四个参数fov, aspect, near, far构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。
image.png
image.png

  1. 渲染器
// 3.创建渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setSize(width,height)
// 实际上这一步生成的canvas画布
renderer.render(scene,camera) //执行渲染操作,类比相机的拍照动作,场景使用scene,相机用camera

// 把canvas添加到html上
document.body.appendChild(renderer.domElement)

显示三维坐标轴

image.png

光源对物体表面的影响

  1. 基础网格材质MeshBasicMaterial不受光照影响

  2. 在这里插入图片描述

  3. 漫反射网格材质MeshLambertMaterial(opens new window)会受到光照影响,该材质也可以称为Lambert网格材质,音译为兰伯特网格材质。

// 创建光源对象,点光源
const pointLight = new THREE.PointLight(0xffffff,1.0)
// 光源衰减,默认值2.0,设置为0就是光源不随空间而进行强度变化
pointLight.decay = 0.0
// 光源放置位置
pointLight.position.set(400,200,200)
// 可视化点光源
const pointLightHelper = new THREE.PointLightHelper(pointLight,10)
// 把光源添加到场景中
scene.add(pointLight)
scene.add(pointLightHelper)
  1. 环境光AmbientLight没有特定方向,只是整体改变场景的光照明暗。平行光DirectionalLight就是沿着特定方向发射。

相机控件轨道控制器

  1. 引入

image.png

// 创建相机空间实例化对象
const control = new OrbitControls(camera, renderer.domElement)
control.addEventListener('change',function() {
  // 渲染
  renderer.render(scene,camera)
})

动画渲染

// 周期性执行,默认状态60次/秒
function render(){
  // 每次旋转0.01弧度
  mesh.rotateY(0.01)
  renderer.render(scene,camera)
  requestAnimationFrame(render)
}
render()


// canvas宽高动态变化,需要更新相机和渲染的参数
window.onresize = function(){
  // 更新渲染器
  renderer.setSize(window.innerWidth,window.innerHeight)
  // 更新相机
  camera.aspect = window.innerWidth/window.innerHeight
  camera.updateProjectionMatrix()
}

阵列立方体和相机适配

lookAt值改变的同时,controls.target.set的值要和lookAt保持一致
image.png

WebGL渲染器

// 3.创建渲染器
const renderer = new THREE.WebGLRenderer({
  antialias:true, //启用抗锯齿
})
// 设置像素比参考当前屏幕的像素比
renderer.setPixelRatio(window.devicePixelRatio)

GUI.js

import * as THREE from 'three';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
import {GUI} from 'three/addons/libs/lil-gui.module.min.js'

const gui = new GUI()
// 创建一个待改变的对象
const obj = {
  x:30,
  color:0xffffff
}
// 通过gui交互改变obj这个对象里面的属性
// 参数【要改变的对象,要改变对象的某个属性,区间范围(0,100)】
// .step【步长,每次拖动时变化的值】
// .onChange【变化时触发的函数】
gui.add(obj, 'x', 0 ,100).name("新增的名字").step(0.1).onChange(function(val){
  console.log(val);
})
// 颜色选择器
gui.addColor(obj,'color').onChange(function(val){
  Mesh.material.color.set(val)
  console.log(val);
})


// 创建分组
// 创建材质子菜单
// 【父菜单.addFolder('子菜单名称')】
const matFolder = gui.addFolder('材质');
// 材质颜色color
matFolder.addColor(obj, 'color').onChange(function(value){
    material.color.set(value);
});
// 材质高光颜色specular
matFolder.addColor(obj, 'specular').onChange(function(value){
    material.specular.set(value);
});

gui.close() //收起总菜单
matFolder.close() //收起子菜单

平面几何体

const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    80, 0, 0, //顶点2坐标
    80, 80, 0, //顶点3坐标

    0, 0, 0, //顶点4坐标   和顶点1位置相同
    80, 80, 0, //顶点5坐标  和顶点3位置相同
    0, 80, 0, //顶点6坐标
]);
// 以逆时针方向为正面,顺时针为反面
const material = new THREE.MeshBasicMaterial({
    side: THREE.FrontSide, //默认只有正面可见
    side: THREE.DoubleSide, //两面可见
    side: THREE.BackSide, //设置只有背面可见
});

image.png

// 简化写法
const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    80, 0, 0, //顶点2坐标
    80, 80, 0, //顶点3坐标
    0, 80, 0, //顶点4坐标
]);

// Uint16Array类型数组创建顶点索引数据
// 以0,1,2为一个对象,0,2,3为一个对象
const indexes = new Uint16Array([
    // 下面索引值对应顶点位置数据中的顶点坐标
    0, 1, 2, 0, 2, 3,
])

// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组

image.png

层级模型

  1. 创建组对象的作用:要想同时操作多个模型的变化,可以直接对组对象进行操作
const geometry = new THREE.BoxGeometry(20, 20, 20);
const material = new THREE.MeshLambertMaterial({color: 0x00ffff});
const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);

mesh2.translateX(50)

// 创建一个组对象
const group = new THREE.Group()
// 把网格模型1,2,作为组对象group的子对象存在
group.add(mesh1)
group.add(mesh2)

// 整个组对象一起动
group.translateX(50)

// 网络模型也可以作为组对象的子对象存在
mesh1.add(mesh2)
  1. 给组对象加以命名
const group1 = new THREE.Group(); //所有高层楼的父对象
group1.name = '高层'
  1. 遍历所有节点
model.add(group1, group2);
// 递归遍历所有模型节点
model.traverse(function(obj){
  console.log(obj.name);
  // obj.isMesh是否是网格模型
})
// 获取对应名称的某个节点,和js一个意思
console.log(model.getObjectByName('1号楼'));
  1. 获取世界坐标
mesh.position.x = 50
// 创建三维向量表示坐标
const v3 = new THREE.Vector3()
console.log(mesh.getWorldPosition(v3));
  1. 给网格模型单独加个坐标系
const meshAxesHelper = new THREE.AxesHelper(50)
mesh.add(meshAxesHelper)

image.png

  1. 改变模型相对坐标系的位置
// 默认情况下,模型的几何中心和坐标系的原点是重合的
geometry.translate(40,0,0)
  1. 隐藏与删除模型
scene.remove(mesh)  //删除
mesh.visible = false  //显示/隐藏:Boolean


const material = new THREE.MeshLambertMaterial({color: 0x00ffff});
const mesh = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);

// 如果给材质设置这个属性,那么所有使用这个材质的网格模型,都会被隐藏,因为他们公用一个材质
material.visible = false

贴图

  1. 纹理贴图
const geometry = new THREE.PlaneGeometry(100, 100); 
// 创建纹理加载器对象
const loadTex = new THREE.TextureLoader()
// 加载图片返回纹理对象
const texture = loadTex.load('earth.jpg')
const material = new THREE.MeshLambertMaterial({
    color: 0x00ffff,
    // 把图片作为模型的贴图
    map:texture
});
const mesh = new THREE.Mesh(geometry, material);

只使用颜色背景和采用图片作为纹理的对比:
image.pngimage.png
类似的,还可以贴在球体/正方体上:

const geometry = new THREE.SphereGeometry(50); 
const geometry = new THREE.BoxGeometry(100,100,100); 

image.pngimage.png

  1. UV坐标
import * as THREE from 'three';

const geometry = new THREE.BufferGeometry(); //创建一个几何体对象
//类型数组创建顶点数据
const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    160, 0, 0, //顶点2坐标
    160, 80, 0, //顶点3坐标
    0, 80, 0, //顶点4坐标
]);
// 创建属性缓冲区对象
const attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;

// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
    0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组

// 将纹理图片,通过uv左边,映射一部分到几何体上
const uvs = new Float32Array([
  0, 0, //左下
  0.5, 0, //右下
  1, 1, //右上
  0, 1, //左上
]);
geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2);
//纹理贴图加载器TextureLoader
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('./earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture, //map表示材质的颜色贴图属性
});
const mesh = new THREE.Mesh(geometry, material);

export default mesh;

image.png

  1. texture阵列【瓷砖案例】
const geometry = new THREE.PlaneGeometry(2000, 2000);

// 创建纹理加载器对象
const loadTex = new THREE.TextureLoader()
// 加载图片返回纹理对象
const texture = loadTex.load('瓷砖.jpg')

// 设置阵列模式
texture.wrapT = THREE.RepeatWrapping
texture.wrapS = THREE.RepeatWrapping

// 选择阵列模式下的重复数量
texture.repeat.set(12,12)

const material = new THREE.MeshLambertMaterial({
    // color: 0x00ffff,
    map: texture
});
const mesh = new THREE.Mesh(geometry, material);

// three.js默认显示平面是XOY平面,且背面不可见
mesh.rotateX(-Math.PI/2)

image.png

  1. 透明背景的png贴图
// 添加一个辅助网格地面
// size:坐标格的尺寸,默认为10
// 坐标格细分次数
// 中线颜色
// 坐标格网格线颜色
const gridHelper = new THREE.GridHelper(300, 25, 0x004444, 0x004444);
scene.add(gridHelper);

// 需要设置背景透明的png作为贴图只需要加上
const material = new THREE.MeshLambertMaterial({
    map: texture,//map表示材质的颜色贴图属性
    transparent:true,//开启透明,这样png贴图的透明部分不显示
});
const mesh = new THREE.Mesh(geometry, material);

mesh.rotateX(-Math.PI/2);
// 让地面适当向下平移1,防止冲突
mesh.position.y = 1;

image.png

  1. UV动画

正常情况下,设置偏移,缺失的部分会显示背景色

const geometry = new THREE.PlaneGeometry(200, 20);
//纹理贴图加载器TextureLoader
const texLoader = new THREE.TextureLoader();
// .load()方法加载图像,返回一个纹理对象Texture
const texture = texLoader.load('./纹理1.jpg');

const material = new THREE.MeshLambertMaterial({
  // 图片和颜色会叠加
    color:0x00ffff,
    map: texture,//map表示材质的颜色贴图属性
});
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI/2);


// 纹理对象的偏移属性
// 本质上是修改的uv顶点坐标
texture.offset.x = -0.5   //u方向偏移

如果改变映射方式,缺失的部分会重新绕回,补全

// 改变映射方式
texture.wrapS = THREE.RepeatWrapping

image.png
image.png
渲染的时候给定偏移量,就可以得出类似于跑马灯的效果

// 渲染循环
function render() {
    texture.offset.x += 0.001
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

跑马灯.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值