常用three.js
x 左右
y 上下
z 前后
const model = new THREE.Group();
// 創建邊界框可視化輔助對象,顏色為黃色
const box = new THREE.Box3().setFromObject(模型);
const helper = new THREE.Box3Helper(box, 0xffff00)
const box3 = new THREE.Box3().setFromObject(模型);
const box3Helper = new THREE.Box3Helper(box3, 0xff0000);
scene.add(box3Helper);
背景色
const renderer = new THREE.WebGLRenderer({
antialias: true, //設置抗鋸齒
alpha:false, //透明開啟與關閉
logarithmicDepthBuffer:true, //能解決部分模型沖突閃爍的問題
});
renderer.setSize(Width, Height);
renderer.setPixelRatio(window.devicePixelRatio) //告訴three.js瀏覽器的像素比,防止模糊
document.getElementById("dineas").appendChild(renderer.domElement);
//設置背景色
renderer.setClearColor(0x444444) //設置背景色
renderer.setClearColor(0x444444,0) //也可以加透明
//透明度
renderer.setClearAlpha(0)
軌道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// 引入軌道控制器
this.controls = new OrbitControls(this.camera, this.renderer.domElement );
//創建軌道控制器(相機,渲染器)
//創建動畫
animate() {
requestAnimationFrame(this.animate);
this.renderer.render(this.scene, this.camera);
},
// 設置相機控件軌道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 修改相機指向的位置
controls.target.set(0, 0, 0)
controls.update()
controls.addEventListener('change',function(e){
console.log('camera.position',camera.position);
})
軌道控制器的屬性
controls.enablePan = false
// 禁止右鍵平移(模型true)
controls.enableZoom = false
// 禁止縮放
controls.enableRotate = false
//禁止右鍵旋轉
controls.minDistance = 200
//縮放的最小
controls.maxDistance = 500
//縮放的最大
controls.addEventListener("change",function(){
// 相機位置與目標觀察點的距離
const dis = controls.getDistance()
console.log(dis)
})
controls.minPolarAngle = 0
//上下旋轉的范圍
controls.maxPolarAngle = Math.PI/2
//上下旋轉的范圍
controls.minAzimuthAngle = 0
//左右旋轉的范圍
controls.maxAzimuthAngle = Math.PI/2
//左右旋轉的范圍
添加背景圖
var urls = ['1.png', '1.png','1.png', '1.png','1.png', '1.png',];
scene.background = new THREE.CubeTextureLoader().setPath('/').load(urls)
添加霧
scene.fog = new THREE.Fog( 0xcccccc, 10, 15 );
網格坐標輔助對象.
this.gridHelper = new THREE.GridHelper();
this.scene.add( this.gridHelper );
3維坐標軸
const axesHelper = new THREE.AxesHelper( 5 );
this.scene.add( axesHelper );
獲取網格模型的世界坐標
const posit = new THREE.Vector3()
mesh.getWorldPosition(posit)
console.log(posit,"模型的世界坐標")
移動物體或相機
this.物體.position.set(0,3,0)
this.物體.position.x = 1
this.物體.position.z = 1
this.物體.position.y = 1
縮放物體
this.物體.scale.set(1,2,3)
this.物體.scale.x = 1
this.物體.scale.z = 1
this.物體.scale.y = 1
旋轉物體
this.物體.rotation.set(Math.PI/4,0,0)
//Math.PI圓周率
this.物體.rotation.set(Math.PI/4,0,0,"xzy")
//可添加旋轉順序
this.物體.rotation.x = 1
this.物體.rotation.z = 1
this.物體.rotation.y = 1
this.物體.rotateY(0.01)
gsap 通過gsap插件設置動畫
npm i gsap //安裝
import gsap from 'gsap'; //引入
let animation = gsap.to(this.cube.position, {
z: 5, //方向
duration: 5, //時間
ease: "power1.inOut", //動畫運動方式
repeat: -1, //動畫次數 -1無限次
yoyo:true, //往返運行
delay:2, //延時時間
onComplete: () => {
console.log("動畫結束")
},
onStart: () => {
console.log("動畫開始")
}
})
// gsap.to(this.cube.rotation, { y: 2 * Math.PI, duration: 5 })
//監聽雙擊事件
this.renderer.domElement.addEventListener("dblclick",()=>{
if (animation.isActive()) { //判斷動畫是在運動中還是停止中 true運動中 false停止中
animation.pause() // 設置暫定
}else{
animation.resume() //設置開啟動畫
}
})
監聽頁面變化
// 監聽頁面變化
window.addEventListener("resize",()=>{
console.log("畫面變化了")
// 更新攝像頭
this.camera.aspect = window.innerWidth / window.innerHeight
// 更新攝像機的投影矩陣
this.camera.updateProjectionMatrix()
// 更新渲染器
this.renderer.setSize(window.innerWidth,window.innerHeight)
// 設置渲染器的像素比
this.renderer.setPixelRatio(window.devicePixelRatio)
})
紋理
//紋理
this.textureLoader = new THREE.TextureLoader() //創建紋理
const doorcolor = this.textureLoader.load('./customerY.png') //加載紋理圖
const doorcolor1 = this.textureLoader.load('./customerY.png') //加載紋理圖
console.log(doorcolor,"doorcolor")
// doorcolor.offset.x = 0.5 //設置紋理偏移量
doorcolor.center.set(0.5,0.5) //旋轉中心點
doorcolor.rotation = Math.PI / 4 //旋轉紋理
// 創建物體
this.geometry = new THREE.BoxGeometry(1, 1, 1);
this.material = new THREE.MeshBasicMaterial({
color: 0x00ff00, //物體顏色
map:doorcolor, //物體添加紋理
alphaMap:doorcolor1, //添加透明紋理
transparent:true, //是否透明
side:THREE.DoubleSide //渲染兩面
});
this.cube = new THREE.Mesh(this.geometry, this.material);
this.scene.add(this.cube);
性能檢測
import Stats from 'three/examples/jsm/libs/stats.module.js'; //性能檢測
// 性能檢測
this.Stats = new Stats()
this.$refs.container.appendChild(this.Stats.domElement)
animate() {
this.Stats.update()
requestAnimationFrame(this.animate);
},
創建隨機數
(Math.random()-0.1)*20
//在20以內隨機
渲染器
//創建渲染器
const renderer = new THREE.WebGLRenderer({
antialias:true, //設置抗鋸齒
});
renderer.setSize(window.innerWidth, window.innerHeight);
//渲染的寬高
renderer.setPixelRatio(window.devicePixelRatio)
//告訴three.js瀏覽器的像素比,防止模糊
renderer.setClearColor(0x444444)
// 設置渲染器的背景色
document.getElementById("app").appendChild(renderer.domElement);
//把渲染器插入到那個標簽下
動畫與畫布窗口變化
// 渲染循環
function animate() {
controls.update()
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
// 畫布跟隨窗口變化
window.onresize = function () {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
gui插件
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
//導入插件
const gui = new GUI();
// 實例化一個gui對象
//改變值
gui.add(mesh.position, 'x', 0, 180);
//gui.add(要改變的對象, 要改變的對象名, 改變的最小值, 改變的最大值);
gui.add(obj,'x',0,180).name("測試")
//可以改變顯示的名字
gui.add(obj,'x',0,180).step(0.1)
//改變的步數
//監聽改變的值
gui.add(obj,'x',0,180).name("測試").onChange((value)=>{
console.log(value)
mesh.position.x = value
})
改變顏色
//改變顏色 addColor
gui.addColor(obj,'color').name("測試1").onChange((value)=>{
mesh.material.color.set(value)
})
設置選擇值
//可選擇-100,0,100
gui.add(obj,'scale',[-100,0,100]).name("測試").onChange((value)=>{
mesh.position.x = value
})
//可設置名稱
gui.add(obj,'scale',{left:-100,centter:0,right:100}).name("測試").onChange((value)=>{
mesh.position.x = value
})
//可中文設置
gui.add(obj,'scale',{左:-100,中:0,右:100}).name("測試").onChange((value)=>{
mesh.position.x = value
})
設置單選
gui.add(obj,'danxua').name('是否').onChange((value)=>{
console.log(value)
})
設置分組
const mat = gui.addFolder("材質")
// 設置分組
mat.close()
// 設置默認關閉
mat.add(mesh.position,'y',0,1000)
// 在mat分組上設置
光源與受光源物體
受光照影響材質
光源

點光源
// 創建點光源
const pointLight = new THREE.PointLight(0xffffff,1,100 )
pointLight.position.set( 80,80, 80 );//偏移光源位置,觀察渲染效果變化
pointLight.intensity = 38100;//光照強度
pointLight.distance = 300;// 光的衰減
pointLight.decay = 2;//光照強度
scene.add( pointLight );
環境光
// 環境光
const light = new THREE.AmbientLight( 0x404040 ,4); // 柔和的白光
scene.add( light );
平行光
// 平行光
const directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
// 創建平行光
directionalLight.position.set(100,100,100)
// 創建平行光位置
directionalLight.target = mesh
// 設置平行光執行的物體
scene.add( directionalLight );
聚光源
// // // 聚光源
const spotLight = new THREE.SpotLight(0xffffff,40)
// //創建聚光源,參數一:顏色,參數二:光照強度
spotLight.castShadow = true;
spotLight.angle = Math.PI/15
// //設置聚光源發散角度
spotLight.distance = 300
spotLight.decay = 0
scene.add( spotLight );
spotLight.position.set(0,180,0)
//設置聚光源的位置
spotLight.target.position.set(0,0,0)
// 設置聚光源照的位置
scene.add(spotLight.target)
// 設置聚光源照添加到場景中
幾何體
// 生成一個緩沖幾何體(可以自定義形狀)
const geometry = new THREE.BufferGeometry()
// 創建類型化數組(三個頂點等于一個坐標)
const vertices = new Float32Array([
0,0,0,
50,0,0,
0,100,0,
0,0,10,
0,0,100,
50,0,10
])
const attribute = new THREE.BufferAttribute(vertices,3)
// 屬性緩沖對象表示
console.log(attribute)
geometry.attributes.position = attribute
// 設置幾何體的頂點位置屬性
const material = new THREE.PointsMaterial({color:0xffff00,size:10})
// 創建點材質點材質
const points = new THREE.Points(geometry,material)
// 創建點模型
const line1 = new THREE.Line(geometry,material)
// 創建線模型(會順著鏈接起來,但是最后點和開始點不會鏈接)
const line2 = new THREE.LineLoop(geometry,material)
// 創建線模型(會順著鏈接起來,會閉合線條)
const line3 = new THREE.LineSegments(geometry,material)
// 創建線模型(非連續的線條)
scene.add(line3)
點模型
const points = new THREE.Points(geometry,material)
線模型(會順著鏈接起來,但是最后點和開始點不會鏈接)
const line1 = new THREE.Line(geometry,material)
線模型(會順著鏈接起來,會閉合線條)
const line2 = new THREE.LineLoop(geometry,material)
線模型(非連續的線條)
const line3 = new THREE.LineSegments(geometry,material)
通過網格模型渲染
// 生成一個緩沖幾何體(可以自定義形狀)
const geometry = new THREE.BufferGeometry()
// 創建類型化數組(三個頂點等于一個坐標)
const vertices = new Float32Array([
0,0,0,
50,0,0,
0,100,0,
0,0,10,
0,0,100,
50,0,10
])
const attribute = new THREE.BufferAttribute(vertices,3)
// 屬性緩沖對象表示
console.log(attribute)
geometry.attributes.position = attribute
// 設置幾何體的頂點位置屬性
const material = new THREE.MeshBasicMaterial({
color:0xffff00,
// side:THREE.FrontSide //默認只有正面可見
side:THREE.DoubleSide //兩面可見
// side:THREE.FrontSide //背面可見
})
// 創建網格材質
const mesh = new THREE.Mesh(geometry, material);
// 通過網格模型渲染
通過類型化創建
const vertices = new Float32Array([
0,0,0,
50,0,0,
0,100,0,
50,100,0,
])
const attribute = new THREE.BufferAttribute(vertices,3)
const indexes = new Uint16Array([0,1,2,1,3,2])
// 0表述第一組,1表述第二組,2表示第三組,3表述第四組
//0 = 0,0,0 || 1=50,0,0 || 2=0,100,0 || 3=50,100,0
geometry.index = new THREE.BufferAttribute(indexes,1)
const mesh = new THREE.Mesh(geometry, material);
旋轉、縮放、平移幾何體
居中
geometry.translate(50, 0, 0);//偏移
// 居中:已經偏移的幾何體居中,執行.center(),你可以看到幾何體重新與坐標原點重合
geometry.center();
角度
cube.rotation.y = Math.PI/4
//旋轉角度
設置顏色
material.color.set(0x005001) //十六進制設置顏色
material.color.set('#005001') //css設置顏色
克隆
const cube2 = cube.clone() //克隆
復制
cube2.rotation.copy(cube.rotation) //復制
層級
創建組對象
const geometry = new THREE.BoxGeometry( 100, 100, 100 );
const material = new THREE.MeshBasicMaterial( {color:0xff000f});
const cube1 = new THREE.Mesh( geometry, material );
const cube2 = new THREE.Mesh( geometry, material );
cube2.translateX(150)
// 創建組對象
const group = new THREE.Group()
group.add(cube1) //把物體加入組里
group.add(cube2)
group.add(cube1,cube2) //可以同時添加多個
group.translateX(150) //可以操作組對象,操作組對象,子對象也會同時操作
scene.add(group) //把組放到場景中
遞歸查找所有的子對象
// 遞歸循環所有模型節點
group3.traverse((obj)=>{
// 判斷是否是網格模型
if (obj.type == "Mesh") {
// 是網格模型則修改顏色
obj.material.color.set(0xffffff)
}
console.log(obj,"obj")
})
查找指定模型名稱
const obj = group3.getObjectByName("4號樓")
const obj = gltf.scene.getObjectByName("外殼01")
示例
const group = new THREE.Group()
const group2 = new THREE.Group()
const group3 = new THREE.Group()
group.name = '高層'
for (let i = 0; i < 5; i++) {
const geometry = new THREE.BoxGeometry( 20, 60, 10 );
const material = new THREE.MeshBasicMaterial( {color:0xff000f});
const cube = new THREE.Mesh( geometry, material );
cube.name = (i+1)+"號樓"
cube.translateX(i*40)
cube.translateY(70)
group.add(cube)
}
group2.name = '洋房'
for (let i = 0; i < 5; i++) {
const geometry = new THREE.BoxGeometry( 20, 30, 10 );
const material = new THREE.MeshBasicMaterial( {color:0xff000f});
const cube = new THREE.Mesh( geometry, material );
cube.name = (i+6)+"號樓"
cube.translateX(i*40)
cube.translateZ(40)
group2.add(cube)
}
group3.name = '小區'
group3.add(group,group2)
//可以同時添加多個
scene.add(group3) //把組放到場景中
console.log('group', JSON.parse(JSON.stringify(group)))
// 遞歸循環所有模型節點
group3.traverse((obj)=>{
// 判斷是否是網格模型
if (obj.type == "Mesh") {
// 是網格模型則修改顏色
obj.material.color.set(0xffffff)
}
console.log(obj,"obj")
})
// 查找指定模型名稱
const obj = group3.getObjectByName("4號樓")
obj.material.color.set(0xfff00f)
添加局部坐標
const Helper = new THREE.AxesHelper(50);
cube.add(Helper);
改變物體原點
const geometry = new THREE.BoxGeometry( 20, 20, 20 );
const material = new THREE.MeshLambertMaterial( {color:0xff000f});
const cube = new THREE.Mesh( geometry, material );
geometry.translate(20/2,0,0)
// 改變物體原點
刪除子類
const geometry = new THREE.BoxGeometry( 20, 20, 20 );
const material = new THREE.MeshLambertMaterial( {color:0xff000f});
const cube = new THREE.Mesh( geometry, material );
const cube1 = new THREE.Mesh( geometry, material );
cube1.position.x = 50
const group = new THREE.Group()
group.add(cube,cube1)
group.remove(cube)
// 刪除
顯示隱藏
cube1.visible = false
// 隱藏,可以隱藏材質
紋理
創建紋理貼圖
const geometry = new THREE.SphereGeometry(50);
// 創建一個紋理加載器
const loadtex = new THREE.TextureLoader()
// 加載圖片
const texture = loadtex.load('/earth.jpg')
const material = new THREE.MeshLambertMaterial({
// color: 0xff000f,
// map:texture,//設置材質的顏色貼圖
});
material.map = texture; //可以直接訪問材質屬性設置
const cube = new THREE.Mesh(geometry, material);
自定義uv坐標
// 創建一個紋理加載器
const loadtex = new THREE.TextureLoader()
// 加載圖片
const texture = loadtex.load('/earth.jpg')
// 生成一個緩沖幾何體(可以自定義形狀)
const geometry = new THREE.BufferGeometry()
// 創建類型化數組(三個頂點等于一個坐標)
const vertices = new Float32Array([
0,0,0,
160,0,0,
160,80,0,
0,80,0,
])
const attribute = new THREE.BufferAttribute(vertices,3)
// 屬性緩沖對象表示
console.log(attribute)
geometry.attributes.position = attribute
// 設置幾何體的頂點位置屬性
// Uint16Array類型數組創建頂點索引數據
const indexes = new Uint16Array([0,1,2,0,2,3])
geometry.index = new THREE.BufferAttribute(indexes,1)
const material = new THREE.MeshBasicMaterial({
map:texture,
})
// 創建網格材質
const mesh = new THREE.Mesh(geometry, material);
// 創建uv坐標
const uvs = new Float32Array([
0,0,
1,0,
1,1,
0,1
])
// 通過幾何體的頂點位置設置uv坐標
geometry.attributes.uv = new THREE.BufferAttribute(uvs,2)
scene.add(mesh)
頂點UV坐標可以在0~1.0之間任意取值,紋理貼圖左下角對應的UV坐標是(0,0),右上角對應的坐標(1,1)。

紋理對象陣列(地轉)
const scene = new THREE.Scene();
const gui = new GUI()
const geometry = new THREE.PlaneGeometry(800,800);
// const geometry = new THREE.CircleGeometry( 5, 32 );
// const geometry = new THREE.SphereGeometry(50);
geometry.rotateX(Math.PI/2)
// 創建一個紋理加載器
const loadtex = new THREE.TextureLoader()
// // 加載圖片
const texture = loadtex.load('/瓷磚.jpg')
//陣列
texture.wrapS = THREE.RepeatWrapping //上下開啟陣列
texture.wrapT = THREE.RepeatWrapping //左右開啟陣列
texture.repeat.set(30,30) //上下左右的陣列次數
const material = new THREE.MeshLambertMaterial({
side:THREE.DoubleSide,
map:texture,//設置材質的顏色貼圖
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube)
開啟透明
// 創建一個紋理加載器
const loadtex = new THREE.TextureLoader()
// 加載圖片
const texture = loadtex.load('/轉彎.png')
const material = new THREE.MeshLambertMaterial({
map:texture,//設置材質的顏色貼圖
transparent:true, //開啟透明
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube)
uv偏移量
const geometry = new THREE.PlaneGeometry(50,50);
// 創建一個紋理加載器
const loadtex = new THREE.TextureLoader()
// 加載圖片
const texture = loadtex.load('/轉彎.png')
const material = new THREE.MeshLambertMaterial({
map:texture,//設置材質的顏色貼圖
transparent:true, //開啟透明
});
// uv偏移量
texture.offset.x += 0.5
texture.offset.y += 0.5
texture.wrapS = THREE.RepeatWrapping //被裁掉的自動追加到后面
const cube = new THREE.Mesh(geometry, material);
scene.add(cube)
加載模型
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; //引入GLTF加載器
const scene = new THREE.Scene();
//創建一個GLTF加載器
const loader = new GLTFLoader()
//聲明一個組對象,用來添加加載成功的三維場景
const model = new THREE.Group()
//gltf加載成功后返回一個對象
loader.load('/工廠.gltf',(gltf)=>{
console.log(gltf,"gltf")
//三維場景添加到model組對象中
model.add(gltf.scene)
})
scene.add(model)
// 設置相機控件軌道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 修改相機指向的位置
controls.target.set(-14,-24,10)
controls.update()
單獨給貼紙
//gltf加載成功后返回一個對象
loader.load('/工廠.gltf',(gltf)=>{
console.log(gltf.scene,"gltf")
gltf.scene.traverse((moxin)=>{
if (moxin.isMesh) {
if (moxin.material.map) {
console.log("判斷是否存在貼圖",moxin.material.map.encoding)
}
}
})
//三維場景添加到model組對象中
model.add(gltf.scene)
})
scene.add(model)
// // 創建一個紋理加載器
const loadtex = new THREE.TextureLoader()
// // // 加載圖片
const texture = loadtex.load('/瓷磚.jpg')
texture.encoding = THREE.sRGBEncoding
// 反轉貼圖
texture.flipY = false
renderer.outputColorSpace = THREE.SRGBColorSpace;

PBR材質
MeshStandardMaterial 材質
material.metalness = 1 (0-1)
//金屬度 0表述金屬度低,1表述金屬度高,(值越高越像金屬)
material.roughness = 0.5 (0-1)
//粗糙度 0表述表面光滑,1表示粗糙 (值越高越粗糙)
// CubeTextureLoader環境貼圖,setPath加載的文件夾,load加載的文件,
// 加載環境貼圖
// 加載周圍環境6個方向貼圖
// 上下左右前后6張貼圖構成一個立方體空間
// 'px.jpg', 'nx.jpg':x軸正方向、負方向貼圖 p:正positive n:負negative
// 'py.jpg', 'ny.jpg':y軸貼圖
// 'pz.jpg', 'nz.jpg':z軸貼圖
const texturecube = new THREE.CubeTextureLoader().setPath('/環境貼圖/環境貼圖0/')
.load(['px.jpg','nx.jpg','py.jpg','ny.jpg','pz.jpg','nz.jpg',])
moxin.material.envMap = texturecube
//環境貼圖(給某個物體添加環境貼圖)
moxin.material.envMapIntensity = 1
//環境貼圖的影響程度
給全部物體添加貼圖
// 環境貼圖紋理對象textureCube作為.environment屬性值,影響所有模型
scene.environment = textureCube;
環境貼圖色彩空間編碼.encoding
//如果renderer.outputEncoding=THREE.sRGBEncoding;環境貼圖需要保持一致
textureCube.encoding = THREE.sRGBEncoding;
MeshPhysicalMaterial清漆層
const material = new THREE.MeshPhysicalMaterial( {
clearcoat: 1.0,//物體表面清漆層或者說透明涂層的厚度
clearcoatRoughness: 0.1,//透明涂層表面的粗糙度
color: obj.material.color, //默認顏色
metalness: 0.9,//金屬度
roughness: 0.5,//粗糙度
envMap: textureCube, //環境貼圖
envMapIntensity: 2.5, //環境貼圖對Mesh表面影響程度
} );
//示例
//創建一個GLTF加載器
const loader = new GLTFLoader()
//聲明一個組對象,用來添加加載成功的三維場景
const model = new THREE.Group()
//gltf加載成功后返回一個對象
loader.load('/轎車.glb',(gltf)=>{
console.log(gltf,"gltf")
const obj = gltf.scene.getObjectByName("外殼01")
obj.material = new THREE.MeshPhysicalMaterial({
color: obj.material.color, //默認顏色
metalness: 0.9,//車外殼金屬度
roughness: 0.5,//車外殼粗糙度
envMap: texturecube, //環境貼圖
envMapIntensity: 2.5, //環境貼圖對Mesh表面影響程度
clearcoat:1, //物體表面清漆層或者說透明涂層的厚度
clearcoatRoughness:0, //透明涂層表面的粗糙度
})
model.add(gltf.scene)
},function ( xhr ) {
//加載進度
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},)
scene.add(model)
玻璃
const obj1 = gltf.scene.getObjectByName("玻璃01")
obj1.material = new THREE.MeshPhysicalMaterial({
color: obj1.material.color, //默認顏色
metalness: 0,//車外殼金屬度
roughness: 0,//車外殼粗糙度
envMapIntensity: 0, //環境貼圖對Mesh表面影響程度
transmission: 1.0, //玻璃材質透光率
ior:1.5, ////折射率 非金屬材料的折射率從1.0到2.333。默認值為1.5。
})
相機
正投影相機
let Width = window.innerWidth
let Height = window.innerHeight
const k = Width/Height
const s = 500
const camera = new THREE.OrthographicCamera(-s*k,s*k,s,-s,1,8000)
camera.position.set(0, 2000, 0);
camera.lookAt(2000, 100, 2000); //相機觀察目標指向Three.js坐標系原點
// 設置相機控件軌道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 修改相機指向的位置
controls.target.set(200, 0, 200)
controls.update()
相機屬性
// //相機
const camera = new THREE.PerspectiveCamera(30, Width / Height, 0.1, 3000);
camera.position.set(800, 800, 800); //相機的位置
camera.lookAt(0, 0, 0); //相機看的方向
// 設置相機控件軌道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0) //這里要和 camera.lookAt(0, 0, 0)保持同步
controls.update()
包圍盒
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshLambertMaterial({
color: 0x00ffff,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 包圍盒
const box3 = new THREE.Box3()
box3.expandByObject(mesh) //計算的模型
const size = new THREE.Vector3()
box3.getSize(size) //獲取模型計算的尺寸
console.log(size,"size")
const center = new THREE.Vector3()
box3.getCenter(center) //獲取模型計算的位置
console.log(center,"center")
后期處理
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js"; //效果合成器
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass"; //引入渲染通道
const composer = new EffectComposer(renderer)
//創建效果合成器,renderer渲染器作為參數
const renderpass =new RenderPass(scene,camera)
//創建渲染通道,參數為 scene場景 camera相機
composer.addPass(renderpass)
//效果合成器添加渲染通道
// 渲染循環
function animate() {
renderer.render(scene, camera);
composer.render();
requestAnimationFrame(animate);
}
描邊效果
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass"; //引入描邊效果
// OutlinePass 創建描邊效果 參數一:2維向量 就是畫布的尺寸, scene場景 camera相機
const v2 = new THREE.Vector2(Width,Height)
const outlinePass = new OutlinePass(v2,scene,camera)
// 那個模型需要需要描邊,可以有多個
outlinePass.selectedObjects = [mesh1]
outlinePass.visibleEdgeColor.set(0xffff00)
// 設置描邊的顏色
outlinePass.edgeThickness = 5
// 設置描邊的厚度
outlinePass.edgeStrength = 6
// 設置描邊的亮度
outlinePass.pulsePeriod = 2
// 設置描邊閃爍,0就是不閃爍
// 把描邊添加到效果合成器里
composer.addPass(outlinePass)
發光效果
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
// unrealBloomPass 創建發光效果
const v2 = new THREE.Vector2(Width,Height)
const unrealBloomPass = new UnrealBloomPass(v2)
unrealBloomPass.strength = 1
composer.addPass(unrealBloomPass)
解決顏色偏差
import { GammaCorrectionShader } from "three/examples/jsm/shaders/GammaCorrectionShader.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";
const gammaPass = new ShaderPass(GammaCorrectionShader)
composer.addPass(gammaPass)
選擇模型
選擇單個模型
renderer.domElement.addEventListener('click', function (event) {
// .offsetY、.offsetX以canvas畫布左上角為坐標原點,單位px
const px = event.offsetX;
const py = event.offsetY;
//屏幕坐標px、py轉WebGL標準設備坐標x、y
//width、height表示canvas畫布寬高度
const x = (px / window.innerWidth) * 2 - 1;
const y = -(py / window.innerHeight) * 2 + 1;
//創建一個射線投射器`Raycaster`
const raycaster = new THREE.Raycaster();
//.setFromCamera()計算射線投射器`Raycaster`的射線屬性.ray
// 形象點說就是在點擊位置創建一條射線,射線穿過的模型代表選中
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
//.intersectObjects([mesh1, mesh2, mesh3])對參數中的網格模型對象進行射線交叉計算
// 未選中對象返回空數組[],選中一個對象,數組1個元素,選中兩個對象,數組兩個元素
const intersects = raycaster.intersectObjects([mesh1, mesh2, mesh]);
console.log("射線器返回的對象", intersects);
// intersects.length大于0說明,說明選中了模型
if (intersects.length > 0) {
// 選中模型的第一個模型,設置為紅色
intersects[0].object.material.color.set(0xff0000);
}
})
選擇組模型
const model = new THREE.Group()
const loader = new GLTFLoader()
loader.load('/工廠.gltf', (gltf) => {
console.log(gltf, "gltf")
//三維場景添加到model組對象中
model.add(gltf.scene)
})
scene.add(model)
renderer.domElement.addEventListener('click', function (event) {
const px = event.offsetX;
const py = event.offsetY;
const x = (px / window.innerWidth) * 2 - 1;
const y = -(py / window.innerHeight) * 2 + 1;
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
// 固定設置
//首先找到要設置的組模型
const cunshu = model.getObjectByName("存儲罐")
// 循環設置自定屬性,全部指向父類
for (let i = 0; i < cunshu.children.length; i++) {
const element = cunshu.children[i];
element.traverse(function(obj){
if (obj.isMesh) {
obj.ancestors = element
}
})
}
const intersects = raycaster.intersectObjects(cunshu.children);
composer.addPass(outlinePass)
if (intersects.length > 0) {
//設置發光效果
outlinePass.selectedObjects = [intersects[0].object.aaaaa]
}
})
頁面物體標注html內容
添加基礎標簽
const group = new THREE.Group()
// 創建一個組
let div = document.getElementById('label')
// 選擇在頁面中創建的div
let label = new CSS2DObject(div)
// 創建css,導入標簽
label.position.set(200,200,200)
// 設置標簽的位置
group.add(label)
// 添加到組中
scene.add(group);
// 將組添加到場景中
const css2Renderer = new CSS2DRenderer()
// 標簽渲染
css2Renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("sanwei").appendChild(css2Renderer.domElement);
css2Renderer.domElement.style.position = 'absolute';
css2Renderer.domElement.style.top = '0px';
css2Renderer.domElement.style.pointerEvents = 'none';
// 添加穿透
// 渲染循環
function animate() {
css2Renderer.render(scene, camera);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
可以直接標注到模型
let div = document.getElementById('label')
// 選擇在頁面中創建的div
let label = new CSS2DObject(div)
// 設置標簽的位置
mesh.add(label)
// 可以直接標注到某個模型下
標注到模型的某個點上
let div = document.getElementById('label')
// 選擇在頁面中創建的div
let label = new CSS2DObject(div)
// 設置標簽的位置
mesh.add(label)
// 可以直接標注到某個模型下
const pos = mesh.geometry.attributes.position;
// 獲取幾何體頂點1的xyz坐標,設置標簽局部坐標.position屬性
label.position.set(pos.getX(0),pos.getY(0),pos.getZ(0));
模型動畫
基礎動畫
import * as THREE from 'three';
const geometry = new THREE.BoxGeometry(50, 50, 50);
const material = new THREE.MeshLambertMaterial({ color: 0x00ffff });
const model = new THREE.Mesh(geometry, material);
model.name = 'box'
// 定義模型名字
const times = [0,3,6] //定義時間線0秒,3秒,5秒
const values = [0,0,0 ,100,0,0 ,0,0,100] //定義每秒的位置
// 設置關鍵幀數據THREE.KeyframeTrack(參數一:要加入的關鍵幀,參數二:定義的時間線,參數三:定義的參數位置或改變的狀態)
const posKF = new THREE.KeyframeTrack('box.position',times,values)
const colorKF = new THREE.KeyframeTrack('box.material.color',[2, 5],[1, 0, 0, 0, 0, 1])
// 1.3 AnimationClip表示一個關鍵幀動畫,可以基于關鍵幀數據產生動畫效果
// 創建一個clip關鍵幀動畫對象,命名"test",動畫持續時間6s
// AnimationClip包含的所有關鍵幀數據都放到參數3數組中即可
const clip = new THREE.AnimationClip("test",6,[posKF,colorKF ]);
// 包含關鍵的模型
const mixer = new THREE.AnimationMixer(model)
const clipAction = mixer.clipAction(clip);
clipAction.play()
// 通過Clock對象輔助獲取每次loop()執行的時間間隔。
const clock = new THREE.Clock();
// 執行mixer.update()更新播放器AnimationMixer時間數據
function loop() {
requestAnimationFrame(loop);
const frameT = clock.getDelta();
// 更新播放器相關的時間
mixer.update(frameT);
}
loop();
export default model;
循環方式
clipAction.loop = THREE.LoopOnce //只執行一次
clipAction.loop = THREE.LoopRepeat //重復次數為repetitions的值, 且每次循環結束時候將回到起始動作開始下一次循環。
clipAction.loop = THREE.LoopPingPong //重復次數為repetitions的值, 且像乒乓球一樣在起始點與結束點之間來回循環。
物體狀態停留在動畫結束的時候
clipAction.clampWhenFinished = true;
// 物體狀態停留在動畫結束的時候
停止、播放、暫停
clipAction.play();
//播放動畫
clipAction.stop();
//動畫停止結束,回到開始狀態
clipAction.paused = false //播放
clipAction.paused = true //暫停
//暫停狀態
倍速
clipAction.timeScale = 1;//默認
clipAction.timeScale = 2;//2倍速
播放模型動畫
const loader = new GLTFLoader()
//聲明一個組對象,用來添加加載成功的三維場景
const model = new THREE.Group()
//gltf加載成功后返回一個對象
loader.load('/工廠1.glb', (gltf) => {
console.log(gltf, "gltf")
const clock = new THREE.Clock();
// // 包含關鍵的模型
const mixer = new THREE.AnimationMixer(gltf.scene)
const clipAction = mixer.clipAction(gltf.animations[0]);
clipAction.loop = THREE.LoopOnce //只執行一次
clipAction.play()
// 監聽動畫是否播放完成
mixer.addEventListener('finished',function(){
clipAction.reset() //重制播放
})
function loop() {
requestAnimationFrame(loop);
const frameT = clock.getDelta();
// 更新播放器相關的時間
mixer.update(frameT);
}
loop();
//三維場景添加到model組對象中
model.add(gltf.scene)
})
scene.add(model)
動畫庫tween.js
npm安裝
npm i @tweenjs/tween.js@^18
import TWEEN from '@tweenjs/tween.js';
tweenjs基本語法
let pos = { x: 10, z: 10, y: 10 } //基礎信息
const tween = new TWEEN.Tween(pos) //創建動畫
tween.to({ x: 100, z: 100, y: 100 },2000) // 參數一:{這里面是要改變后的值},參數二:執行的時間
tween.start(); //開始執行
function loop() {
TWEEN.update();//tween更新
requestAnimationFrame(loop);
}
loop();
//第二種寫法
const tween = new TWEEN.Tween(pos).to({ x: 100, z: 100, y: 100 },2000).start();
tweenjs改變threejs模型對象位置
//創建一段mesh平移的動畫
const tween = new TWEEN.Tween(mesh.position);
//經過2000毫秒,pos對象的x和y屬性分別從零變化為100、50
tween.to({x: 100,y: 50}, 2000);
//緩動方式
tween.easing(TWEEN.Easing.Sinusoidal.InOut)
//tween動畫開始執行
tween.start();
//tween動畫停止
tween.stop()
//tween動畫暫停
tween.pause()
//tween動畫繼續執行
tween.pause()
換個語法形式書寫也可以,更簡潔
const tween = new TWEEN.Tween(mesh.position).to({x: 100,y: 50}, 2000).start();
const tween = new TWEEN.Tween(mesh.position)
.to({x: 100,y: 50}, 2000)
.easing(TWEEN.Easing.Sinusoidal.InOut)
.start();
Tweenjs回調函數
twwenjs庫提供了onStart、onUpdate、onComplete等用于控制動畫執行的回調函數。
onStart:動畫開始執行觸發onUpdate:動畫執行過程中,一直被調用執行onComplete:動畫正常執行完觸發
.onUpdate(function(obj){})結構中,obj對應的是new TWEEN.Tween(pos)的參數對象pos。
const tween = new TWEEN.Tween(pos).to({x: 0}, 4000)
// 開始執行:動畫片段tween開始執行的時候觸發onStart
.onStart(function(obj){
...
})
const theEntire = scene.getObjectByName("區域")
let enlarModel = graychoose(event, theEntire.children, camera, '-檔案柜')
console.log(enlarModel, "enlarModel")
console.log(JSON.stringify(enlarModel), "enlarModel")
const options = {
trs: false,
onlyVisible: true,
binary: true,
maxTextureSize: 4096
};
var gltfExporter = new GLTFExporter();
gltfExporter.parse(
enlarModel,
function (result) {
if (result instanceof ArrayBuffer) {
saveArrayBuffer(result, 'scene.glb');
} else {
const output = JSON.stringify(result, null, 2);
console.log(output);
saveString(output, 'scene.gltf');
}
},
function (error) {
console.log('An error happened during parsing', error);
},
options
);
const link = document.createElement('a');
link.style.display = 'none';
document.body.appendChild(link); // Firefox workaround, see #6594
function save(blob, filename) {
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
}
function saveArrayBuffer(buffer, filename) {
save(new Blob([buffer], { type: 'application/octet-stream' }), filename);
}
function saveString(text, filename) {
save(new Blob([text], { type: 'text/plain' }), filename);
}

浙公網安備 33010602011771號