Threejs教程,2024全新系统threejs入门教程

news/2025/2/28 15:23:05/文章来源:https://www.cnblogs.com/KooTeam/p/18606823

Threejs教程,2024全新系统threejs入门教程

https://www.bilibili.com/video/BV1Zm421g7oi/?spm_id_from=333.999.0.0

2 4

01-theejs三要素

WebGL
顶点数据
顶点索引
矩阵

三要素
场景 Scene 容器
相机 Camera 观察
渲染器Renderer 组合

透视相机(PerspectiveCamera)

http://www.webgl3d.cn/

http://www.yanhuangxueyuan.com/threejs/docs/index.html#manual/zh/introduction/Creating-a-scene

TextureLoader 加载本地图片

import * as THREE from "three";
//创建场景
const scene = new THREE.Scene();
// scene.background=new THREE.Color('rgb(222,222,222)')
let loader=new THREE.TextureLoader()
loader.load('./img/mm.jpg',function(texture){scene.background=texture//renderer.render(scene,camera) //重新render
})
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.z = 3;
camera.position.x = 2;
camera.lookAt(0, 0, 0);
//创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)
const cube=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial()
)
scene.add(cube)function animate(){requestAnimationFrame(animate)cube.rotation.x+=0.01cube.rotation.y+=0.01renderer.render(scene,camera)
}
animate()

02-threejss三要素之相机

三要素之相机
正交相机
透视相机
立方相机
立体相机

http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/cameras/PerspectiveCamera

PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )

fov — 摄像机视锥体垂直视野角度
aspect — 摄像机视锥体长宽比
near — 摄像机视锥体近端面
far — 摄像机视锥体远端面

import * as THREE from "three";
//创建场景
const scene = new THREE.Scene();
// scene.background=new THREE.Color('rgb(222,222,222)')
let loader=new THREE.TextureLoader()
loader.load('./img/mm.jpg',function(texture){scene.background=texture//renderer.render(scene,camera) //重新render
})
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
// camera.position.z = 3; //在视野的坐标
// camera.position.x = 2;
camera.position.set(0.4,10)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)
const cube=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial()
)
const cube2=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:0xff0000})
)
cube2.position.x=2
scene.add(cube,cube2)let angle=0
function animate(){requestAnimationFrame(animate)cube.rotation.x+=0.01cube.rotation.y+=0.01const radius=3angle+=0.01camera.position.x=radius*Math.cos(angle)camera.position.z=radius*Math.sin(angle)camera.lookAt(0, 0, 0);renderer.render(scene,camera)
}
animate()

03-threejs三要素之渲染器

WebGLRenderer

import * as THREE from "three";
//创建场景
const scene = new THREE.Scene();
// scene.background=new THREE.Color('rgb(222,222,222)')
let loader=new THREE.TextureLoader()
loader.load('./img/mm.jpg',function(texture){scene.background=texture//renderer.render(scene,camera) //重新render
})
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
// camera.position.z = 3; //在视野的坐标
// camera.position.x = 2;
camera.position.set(0.4,10)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({canvas:document.querySelector('.c1')
});
// renderer.setSize(window.innerWidth,window.innerHeight)
// document.body.appendChild(renderer.domElement)
const cube=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial()
)
const cube2=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:0xff0000})
)
cube2.position.x=2
scene.add(cube,cube2)let angle=0
function animate(){requestAnimationFrame(animate)cube.rotation.x+=0.01cube.rotation.y+=0.01const radius=3angle+=0.01camera.position.x=radius*Math.cos(angle)camera.position.z=radius*Math.sin(angle)camera.lookAt(0, 0, 0);renderer.render(scene,camera)
}
animate()
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>*{margin: 0;padding: 0;}html,body{width: 100%;height: 100%;overflow: hidden;}.wrap{display: flex;}.c1,.c2{margin: 0 10px;border: 1px solid #ccc;}</style>
</head>
<body><div class="wrap"><canvas class="c1" width="500" height="500"></canvas><canvas class="c2" width="500" height="500"></canvas></div><script type="module" src="./main.js"></script>
</body>
</html>
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小canvas:document.querySelector('.c1')
});

04-轨道控制器

轨道控制器
(OrbitControls)

GridHelper 网格

import * as THREE from "three";
//创建场景
const scene = new THREE.Scene();
let loader=new THREE.TextureLoader()
loader.load('./img/mm.jpg',function(texture){scene.background=texture
})
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,200,20)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)
const cube2=new THREE.Mesh(new THREE.BoxGeometry(10,10,10),new THREE.MeshBasicMaterial({color:0xff0000})
)
let grid=new THREE.GridHelper(100,10,0xffffff)
scene.add(grid,cube2)let isDown=false
let startx=0
let currentX=0renderer.domElement.addEventListener('mousedown',(e)=>{isDown=truestartx=e.clientX
})
renderer.domElement.addEventListener('mousemove',(e)=>{if(isDown){const distanceX=e.clientX-startxcurrentX+=distanceX*0.01startx=e.clientXlet radius=40camera.position.x = radius * Math.cos(currentX);camera.position.z = radius * Math.sin(currentX);camera.lookAt(0, 0, 0);}
})
renderer.domElement.addEventListener('mouseup',(e)=>{isDown=false
})function animate(){requestAnimationFrame(animate)renderer.render(scene,camera)
}
animate()

模拟轨道

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();
let loader=new THREE.TextureLoader()
loader.load('./img/mm.jpg',function(texture){scene.background=texturerenderer.render(scene,camera)
})
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,200,20)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)
const cube2=new THREE.Mesh(new THREE.BoxGeometry(10,10,10),new THREE.MeshBasicMaterial({color:0xff0000})
)
let grid=new THREE.GridHelper(100,10,0xffffff)
scene.add(grid,cube2)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})function animate(){requestAnimationFrame(animate)controls.update()// renderer.render(scene,camera)
}
animate()

05-绘制物体的三要素之几何体

绘制:几何体 盒子模型 材质

创建结构 几何体
创建材质 外观
结构和材质组合,生成一个物体

BufferGeometry 接近底层webgl

Float32Array 类型化数组

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();
let loader=new THREE.TextureLoader()
loader.load('./img/mm.jpg',function(texture){scene.background=texturerenderer.render(scene,camera)
})
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,2,20)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)// 创建结构 几何体
// const geometry=new THREE.PlaneGeometry(5,5,10,10)
// const geometry=new THREE.PlaneGeometry(5,5)
const geometry=new THREE.BufferGeometry()
//Float32Array 类型化数组
//一个面有6个点 4 2个三角形
const vertices=new Float32Array([-1.0,-1.0,1.0,1.0,-1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,-1.0,1.0,1.0,-1.0,-1.0,1.0
])
const colors=new Float32Array([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,
])
geometry.setAttribute('position',new THREE.BufferAttribute(vertices,3
))
geometry.setAttribute('color',new THREE.BufferAttribute(colors,3
))// 创建材质 外观
const material=new THREE.MeshBasicMaterial({vertexColors:true,wireframe:true
})
// 结构和材质组合,生成一个物体
const mesh=new THREE.Mesh(geometry,material
)
let grid=new THREE.GridHelper(100,10,0xffffff)
scene.add(grid,mesh)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})function animate(){requestAnimationFrame(animate)controls.update()// renderer.render(scene,camera)
}
animate()

06-绘制物体的三要素之材质

物体三要素之材质
Material

Material
皮肤设置:颜色 纹理 光照响应
材质种类:
MeshBasicMaterial 不受光影响
MeshStandardMaterial受光影响
漫反射
镜面反射

​ 高光
​ 哑光

灯光

.roughness:Float材质的粗糙程度,0.0表示平滑的镜面反射,1.0表示完全漫反射。默认值为
1.0,如果还提供roughnessMap,则两个值相乘。

threejs.org/docs/index.html

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();
let loader=new THREE.TextureLoader()
let texture=loader.load('./img/mm.jpg')
//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,2,20)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)//灯光
const ambientLight=new THREE.AmbientLight(0x404040)
const directionLight=new THREE.DirectionalLight(0xffffff,0.5) //单独背部 不照到
directionLight.position.set(3,3,3)scene.add(ambientLight,directionLight)// 创建结构 几何体
const geometry=new THREE.SphereGeometry(2,32,32)// 创建材质 外观
// const material=new THREE.MeshBasicMaterial({
//     // color:0xff0000,
//     map:texture
// })
const material=new THREE.MeshStandardMaterial({// color:0xff0000,// emissive:0xff0000,//没光 物体自带颜色map:texture,roughness:0.5,metalness:0.5
})
// 结构和材质组合,生成一个物体
const mesh=new THREE.Mesh(geometry,material
)
scene.add(mesh)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})function animate(){requestAnimationFrame(animate)controls.update()renderer.render(scene,camera)
}
animate()

07-贴图详解

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();
// let loader=new THREE.TextureLoader()
// let texture=loader.load('./img/mm.jpg')
let image=new Image()
image.src='./img/mm.jpg'
let texture=new THREE.Texture(image)
image.onload=()=>{texture.needsUpdate=true
}//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,2,20)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)//灯光
const ambientLight=new THREE.AmbientLight(0x404040)
const directionLight=new THREE.DirectionalLight(0xffffff,0.5) //单独背部 不照到
directionLight.position.set(3,3,3)scene.add(ambientLight,directionLight)// 创建结构 几何体
const geometry=new THREE.SphereGeometry(2,32,32)// 创建材质 外观
// const material=new THREE.MeshBasicMaterial({
//     // color:0xff0000,
//     map:texture
// })
const material=new THREE.MeshStandardMaterial({// color:0xff0000,// emissive:0xff0000,//没光 物体自带颜色map:texture,roughness:0.5,metalness:0.5,//对应纹理 更逼真 需要对应的图片aoMap:texture,roughnessMap:texture,displacementMap:texture,normalMap:texture
})
// 结构和材质组合,生成一个物体
const mesh=new THREE.Mesh(geometry,material
)
scene.add(mesh)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})function animate(){requestAnimationFrame(animate)controls.update()renderer.render(scene,camera)
}
animate()

08-光照详解

AmbientLight 环境光 全面 没有shadow

平行光(DirectionalLight)太阳光 有shadow

半球光(HemisphereLight)上下 俩面不同

点光源(PointLight) 从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();
// let loader=new THREE.TextureLoader()
// let texture=loader.load('./img/mm.jpg')
let image=new Image()
image.src='./img/mm.jpg'
let texture=new THREE.Texture(image)
image.onload=()=>{texture.needsUpdate=true
}//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,2,20)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)//灯光
const ambientLight=new THREE.AmbientLight(0x404040)
const directionLight=new THREE.DirectionalLight(0xffffff,0.5) //单独背部 不照到
directionLight.position.set(3,3,3)
const directionLightHelper=new THREE.DirectionalLightHelper(directionLight)
// scene.add(ambientLight,directionLight)
// scene.add(directionLight,directionLightHelper)// const hemisphereLight=new THREE.HemisphereLight(0xff0000,0x00ff00,1)
// scene.add(hemisphereLight)const pointLight=new THREE.PointLight(0xff0000,1,100)
const pointLightHelper=new THREE.PointLightHelper(pointLight,1)
pointLight.position.set(0,5,0)
scene.add(pointLight,pointLightHelper)// 创建结构 几何体
const geometry=new THREE.SphereGeometry(2,32,32)// 创建材质 外观
// const material=new THREE.MeshBasicMaterial({
//     // color:0xff0000,
//     map:texture
// })
const material=new THREE.MeshStandardMaterial({// color:0xff0000,// emissive:0xff0000,//没光 物体自带颜色map:texture,roughness:0.5,metalness:0.5,//对应纹理 更逼真 需要对应的图片// aoMap:texture,// roughnessMap:texture,// displacementMap:texture,// normalMap:texture
})
// 结构和材质组合,生成一个物体
const mesh=new THREE.Mesh(geometry,material
)
scene.add(mesh)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})function animate(){requestAnimationFrame(animate)controls.update()renderer.render(scene,camera)
}
animate()

09-阴影投射详解

阴影投射:光源 物体 渲染器

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();
// let loader=new THREE.TextureLoader()
// let texture=loader.load('./img/mm.jpg')
let image=new Image()
image.src='./img/mm.jpg'
let texture=new THREE.Texture(image)
image.onload=()=>{texture.needsUpdate=true
}//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,50,50)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.shadowMap.enabled=true
document.body.appendChild(renderer.domElement)//灯光
const ambientLight=new THREE.AmbientLight(0x404040)
scene.add(ambientLight)
const directionLight=new THREE.DirectionalLight(0xffffff,1) //单独背部 不照到
directionLight.castShadow=true
directionLight.shadow.mapSize.width=2048 //阴影清晰
directionLight.shadow.mapSize.height=2048
directionLight.position.set(120,20,0)
const directionLightHelper=new THREE.DirectionalLightHelper(directionLight,5)
scene.add(directionLight,directionLightHelper)const pointLight=new THREE.PointLight(0xff0000,200,100)
const pointLightHelper=new THREE.PointLightHelper(pointLight,1)
pointLight.castShadow=true
pointLight.position.set(10,10,0)
scene.add(pointLight,pointLightHelper)// 创建结构 几何体
const geometry=new THREE.PlaneGeometry(100,200)
// 创建材质 外观
const material=new THREE.MeshStandardMaterial({color:0xffffff,
})
// 结构和材质组合,生成一个物体
const mesh=new THREE.Mesh(geometry,material
)
mesh.rotation.x=-Math.PI/2;
mesh.receiveShadow=trueconst mesh2=new THREE.Mesh(new THREE.BoxGeometry(10,10,10),new THREE.MeshStandardMaterial({color:0xff0000})
)
mesh.position.set(0,-5,0)
mesh2.castShadow=true
scene.add(mesh,mesh2)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})
let angle=0
function animate(){angle+=0.01pointLight.position.x=10* Math.cos(angle)pointLight.position.z=10* Math.sin(angle)requestAnimationFrame(animate)controls.update()renderer.render(scene,camera)
}
animate()

10-raycaster射线详解

光线投射Raycaster

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0,30,30)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)const ambientLight=new THREE.AmbientLight(0x404040)
scene.add(ambientLight)const mesh=new THREE.Mesh(new THREE.SphereGeometry(1,30,30),new THREE.MeshStandardMaterial({color:0xff0000})
)
const mesh2=new THREE.Mesh(new THREE.SphereGeometry(1,30,30),new THREE.MeshStandardMaterial({color:0xff0000})
)
const mesh3=new THREE.Mesh(new THREE.SphereGeometry(1,30,30),new THREE.MeshStandardMaterial({color:0xff0000})
)
mesh.position.set(3,0,0)
mesh3.position.set(-3,0,0)
scene.add(mesh,mesh2,mesh3)// 光线投射Raycaster
const raycaster=new THREE.Raycaster()
const rayOrigin=new THREE.Vector3(-6,0,0)
const rayDirection=new THREE.Vector3(1,0,0)
raycaster.set(rayOrigin,rayDirection)let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})let meshs=[mesh,mesh2,mesh3]
const clock=new THREE.Clock()
function animate(){const elapseTime=clock.getElapsedTime()const intersects=raycaster.intersectObjects(meshs)mesh.position.y=4*Math.sin(elapseTime*0.5)mesh2.position.y=4*Math.sin(elapseTime*0.8)mesh3.position.y=4*Math.sin(elapseTime*1.5)for(const mesh of meshs){mesh.material.color.set(new THREE.Color(0xff0000))}for(const intersectObj of intersects){intersectObj.object.material.color.set(new THREE.Color(0x00eef3))}requestAnimationFrame(animate)controls.update()renderer.render(scene,camera)
}
animate()

11-raycaster实现选中物体变色

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//创建场景
const scene = new THREE.Scene();//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0,30,30)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)const ambientLight=new THREE.AmbientLight(0x404040)
scene.add(ambientLight)const mesh=new THREE.Mesh(new THREE.SphereGeometry(1,30,30),new THREE.MeshStandardMaterial({color:0xff0000})
)
const mesh2=new THREE.Mesh(new THREE.SphereGeometry(1,30,30),new THREE.MeshStandardMaterial({color:0xff0000})
)
const mesh3=new THREE.Mesh(new THREE.SphereGeometry(1,30,30),new THREE.MeshStandardMaterial({color:0xff0000})
)
mesh.position.set(3,0,0)
mesh3.position.set(-3,0,0)
scene.add(mesh,mesh2,mesh3)
let meshs=[mesh,mesh2,mesh3]// 光线投射Raycaster
const raycaster=new THREE.Raycaster()const mouse=new THREE.Vector2()
window.addEventListener('mousedown',(event)=>{//浏览器坐标 转 标准坐标mouse.x=(event.clientX/window.innerWidth)*2-1mouse.y=-(event.clientY/window.innerHeight)*2+1raycaster.setFromCamera(mouse,camera)const intersects=raycaster.intersectObjects(meshs)for(const mesh of meshs){mesh.material.color.set(new THREE.Color(0xff0000))}for(const intersectObj of intersects){intersectObj.object.material.color.set(new THREE.Color(0x00eef3))}
})let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})function animate(){requestAnimationFrame(animate)controls.update()renderer.render(scene,camera)
}
animate()

12-模拟物理运动1

cannon物理引擎库

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import * as CANNOU from 'cannon'
//创建场景
const scene = new THREE.Scene();
scene.background=new THREE.Color(0xbfd1e5)//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,3,10)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.shadowMap.enabled=true
document.body.appendChild(renderer.domElement)//灯光
const directionLight=new THREE.DirectionalLight(0xffffff,1) //单独背部 不照到
directionLight.position.set(5,10,7.5)
scene.add(directionLight)// 结构和材质组合,生成一个物体
//创建地面
const plane=new THREE.Mesh(new THREE.PlaneGeometry(20,20),new THREE.MeshStandardMaterial({color:0x808080,})
)
plane.rotation.x=-Math.PI/2;//创建小球
const redius=1
const sphere=new THREE.Mesh(new THREE.SphereGeometry(redius,32,32),new THREE.MeshStandardMaterial({color:0xff0000})
)
sphere.position.set(0,10,0)scene.add(plane,sphere)//创建物理世界
let world=new CANNOU.World()
world.gravity.set(0,-9.8,0) //世界重力多少
//创建物理材料
const groundMaterial=new CANNOU.Material('groundMaterial')
const sphereMaterial=new CANNOU.Material('sphereMaterial')
const contactMeterial=new CANNOU.ContactMaterial(groundMaterial,sphereMaterial,{restitution:0.8,//0不弹 1持续}
)
world.addContactMaterial(contactMeterial)//创建物理地面
const groundBody=new CANNOU.Body({mass:0,//是否有引力  地面默认没shape:new CANNOU.Plane(),material:groundMaterial
})
groundBody.quaternion.setFromEuler(-Math.PI/2,0,0) //position
world.addBody(groundBody)//创建物理小球
const sphereBody=new CANNOU.Body({mass:1,// position:new CANNOU.Vec3(0,3,0),position:sphere.position,material:sphereMaterial
})
const sphereShape=new CANNOU.Sphere(redius)
sphereBody.addShape(sphereShape)
world.addBody(sphereBody)const updatePhysic=()=>{world.step(1/60)sphere.position.copy(sphereBody.position)
}let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})//渲染循环
const clock=new THREE.Clock()
function animate(){const elapsedTime=clock.getElapsedTime()updatePhysic()controls.update()renderer.render(scene,camera)requestAnimationFrame(animate)
}
animate()

13-物理运动-小球发射

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import * as CANNOU from 'cannon'
//创建场景
const scene = new THREE.Scene();
scene.background=new THREE.Color(0xbfd1e5)//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2,3,10)
camera.lookAt(0, 0, 0);//改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias:true,//像素变小 锯齿小
});
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.shadowMap.enabled=true
document.body.appendChild(renderer.domElement)//灯光
const directionLight=new THREE.DirectionalLight(0xffffff,1) //单独背部 不照到
directionLight.position.set(5,10,7.5)
scene.add(directionLight)// 结构和材质组合,生成一个物体
//创建地面
const plane=new THREE.Mesh(new THREE.PlaneGeometry(20,20),new THREE.MeshStandardMaterial({color:0x808080,})
)
plane.rotation.x=-Math.PI/2;//创建小球
const redius=1
const sphere=new THREE.Mesh(new THREE.SphereGeometry(redius,32,32),new THREE.MeshStandardMaterial({color:0xff0000})
)
sphere.position.set(-5,10,0)scene.add(plane,sphere)//创建物理世界
let world=new CANNOU.World()
world.gravity.set(0,-9.8,0) //世界重力多少
//创建物理材料
const groundMaterial=new CANNOU.Material('groundMaterial')
const sphereMaterial=new CANNOU.Material('sphereMaterial')
const contactMeterial=new CANNOU.ContactMaterial(groundMaterial,sphereMaterial,{restitution:0.8,//0不弹 1持续}
)
world.addContactMaterial(contactMeterial)//创建物理地面
const groundBody=new CANNOU.Body({mass:0,//是否有引力  地面默认没shape:new CANNOU.Plane(),material:groundMaterial
})
groundBody.quaternion.setFromEuler(-Math.PI/2,0,0) //position
world.addBody(groundBody)//创建物理小球
const sphereBody=new CANNOU.Body({mass:1,// position:new CANNOU.Vec3(0,3,0),position:sphere.position,material:sphereMaterial,linearDamping:0.5,//空气阻力
})
const sphereShape=new CANNOU.Sphere(redius)
sphereBody.addShape(sphereShape)
sphereBody.applyLocalForce(new CANNOU.Vec3(100,0,0),//用多少力  和球的质量有关massnew CANNOU.Vec3(0,-10,0) //击中球的上中下位置 0中 10上一点 -10下前后回跑 和台球一样
)
world.addBody(sphereBody)const updatePhysic=()=>{world.step(1/60)sphere.position.copy(sphereBody.position)sphere.quaternion.copy(sphereBody.quaternion)
}let controls=new OrbitControls(camera,renderer.domElement)
controls.enableDamping=true //惯性
controls.addEventListener('change',()=>{renderer.render(scene,camera)
})//渲染循环
const clock=new THREE.Clock()
function animate(){const elapsedTime=clock.getElapsedTime()updatePhysic()controls.update()renderer.render(scene,camera)requestAnimationFrame(animate)
}
animate()

小球法射

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
//创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbfd1e5);//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2, 3, 10);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);//灯光
const directionLight = new THREE.DirectionalLight(0xffffff, 1); //单独背部 不照到
directionLight.position.set(5, 10, 7.5);
scene.add(directionLight);// 结构和材质组合,生成一个物体
//创建地面
const plane = new THREE.Mesh(new THREE.PlaneGeometry(20, 20),new THREE.MeshStandardMaterial({color: 0x808080,})
);
plane.rotation.x = -Math.PI / 2;scene.add(plane);//创建物理世界
let world = new CANNOU.World();
world.gravity.set(0, -9.8, 0); //世界重力多少
//创建物理材料
const groundMaterial = new CANNOU.Material("groundMaterial");
const sphereMaterial = new CANNOU.Material("sphereMaterial");
const contactMeterial = new CANNOU.ContactMaterial(groundMaterial,sphereMaterial,{restitution: 0.8, //0不弹 1持续}
);
world.addContactMaterial(contactMeterial);//创建物理地面
const groundBody = new CANNOU.Body({mass: 0, //是否有引力  地面默认没shape: new CANNOU.Plane(),material: groundMaterial,
});
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); //position
world.addBody(groundBody);let spheres=[]
const createSphere = (position, direction) => {//创建可视化小球const redius = 1;const sphere = new THREE.Mesh(new THREE.SphereGeometry(redius, 32, 32),new THREE.MeshStandardMaterial({ color: 0xff0000 }));sphere.position.copy(position);scene.add(sphere);//创建物理小球const sphereBody = new CANNOU.Body({mass: 1,material: sphereMaterial,linearDamping: 0.5, //空气阻力});const sphereShape = new CANNOU.Sphere(redius);sphereBody.position.copy(position)sphereBody.addShape(sphereShape);sphereBody.applyLocalForce(direction.scale(600), //用多少力  和球的质量有关massnew CANNOU.Vec3(0, 0, 0) //击中球的上中下位置 0中 10上一点 -10下前后回跑 和台球一样);world.addBody(sphereBody);spheres.push({sphere,sphereBody})
};renderer.domElement.addEventListener("mouseup", (event) => {let mouse = new THREE.Vector2();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;//射线const raycaster = new THREE.Raycaster();raycaster.setFromCamera(mouse, camera);const pos = new THREE.Vector3();pos.copy(raycaster.ray.direction);pos.add(raycaster.ray.origin);const direction = new CANNOU.Vec3(raycaster.ray.direction.x,raycaster.ray.direction.y,raycaster.ray.direction.z);createSphere({x:pos.x,y:pos.y,z:pos.z}, direction);
});const updatePhysic = () => {world.step(1 / 60);spheres.forEach(({sphere,sphereBody})=>{sphere.position.copy(sphereBody.position);sphere.quaternion.copy(sphereBody.quaternion);})};let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);
});//渲染循环
const clock = new THREE.Clock();
function animate() {const elapsedTime = clock.getElapsedTime();updatePhysic();controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();

14-加载3D模型

8.1 支持的模型类型
Three.js 支持加载多种模型文件格式,常见的包括:
alrE Lal albaTE CL Teancmleelon Cormat Khe

gitf obj fbx clollada ply stl vrml 3ds json

Three.js 提供了多种加载器(Loaders)来支持上述模型格式的加载,例如:
GLTFLoader 用于加载 gITF 文件。
OBJLoader 用于加载 OBJ 文件。
FBXLoader 用于加载 FBX 文件。
ColladaLoader 用于加载 Collada 文件.
TDSLoader用于加载 3DS 文件。
JSONLoader 用于加载 Three.js 的 JSON 格式文件。

https://www.cgmodel.com/model/752945.html

https://juejin.cn/post/6911217131254185991

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
//创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbfd1e5);//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0, 500, 300);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);//灯光
const ambientLight=new THREE.AmbientLight(0x404040)
const directionLight = new THREE.DirectionalLight(0xffffff, 1); //单独背部 不照到
directionLight.position.set(5, 10, 7.5);
scene.add(ambientLight,directionLight);let fbxLoader=new FBXLoader()
let process=document.querySelector('.process')
fbxLoader.load('./mod/Aerith(Kamura Dress).fbx',(fbx)=>{console.log(fbx,8888)//fbx 看属性加 fbx.sence fbxfbx.children.forEach(item=>{let mesh=item.clone()let color=mesh.material.colormesh.material=new THREE.MeshPhongMaterial({color})scene.add(mesh)})
},(xhr)=>{const percent=(xhr.loaded/xhr.total)*100process.textContent= `${Math.round(percent,2)}%`
},(err)=>{console.log(err.message)
})let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);
});//渲染循环
function animate() {controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();

15-控制模型动画

AnimationClip 动画

https://blog.csdn.net/qq_35459724/article/details/134259599

默认太小了

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import _ from 'lodash'let btn=document.getElementById('btn')
btn.onclick=()=>{location.reload();
}//创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbfd1e5);//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(30, 269, 516);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);//灯光
const ambientLight=new THREE.AmbientLight(0xffffff,1)
const directionLight = new THREE.DirectionalLight(0xffffff, 1); //单独背部 不照到
directionLight.position.set(0, 5, 0);
scene.add(ambientLight,directionLight);let modloader=new GLTFLoader()
let process=document.querySelector('.process')
let mixer,runAction,idleAction,currentAction
modloader.load('./mod/girl.glb',(mod)=>{console.log(mod,8888)const model=mod.scenemodel.scale.set(100, 100, 100);const animations=mod.animationsconsole.log(animations)mixer=new THREE.AnimationMixer(model)const runClip=animations.find(clip=>clip.name==='run')const idleClip=animations.find(clip=>clip.name==='idle')if(runClip&&idleClip){runAction=mixer.clipAction(runClip)idleAction=mixer.clipAction(idleClip)idleAction.play()currentAction=idleAction}//随机// mixer.clipAction(randomAction(animations)).play()scene.add(model)
},(xhr)=>{const percent=(xhr.loaded/xhr.total)*100process.textContent= `${Math.round(percent,2)}%`
},(err)=>{console.log(err.message)
})const randomAction=(animations)=>{return _.shuffle(animations)[0]
}let flag=false
window.addEventListener('click',(event)=>{flag=!flagif(flag){if(runAction&&currentAction!==runAction){currentAction.fadeOut(0.5)runAction.reset().fadeIn(0.5).play()currentAction=runAction}}else{if(idleAction&&currentAction!==idleAction){currentAction.fadeOut(0.5)idleAction.reset().fadeIn(0.5).play()currentAction=idleAction}}
})let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);// console.log(camera.position)
});//渲染循环
const clock=new THREE.Clock()
function animate() {const elapsedTime=clock.getDelta()if(mixer)mixer.update(elapsedTime);controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();

16-3D看房案例1

全景图-球体 / 立方体4个面

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import _ from 'lodash'let btn=document.getElementById('btn')
btn.onclick=()=>{location.reload();
}//创建场景
const scene = new THREE.Scene();//创建相机
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0,0,30);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);let textureload=new THREE.TextureLoader()//换全景图6个就行了
let imgs=['./img/mm.jpg','./img/mm.jpg','./img/mm.jpg','./img/mm.jpg','./img/mm.jpg','./img/mm.jpg',
]
let materials=[]
imgs.forEach(item=>{const texture=textureload.load(item)const material=new THREE.MeshBasicMaterial({map:texture})materials.push(material)
})const cube=new THREE.Mesh(new THREE.BoxGeometry(40,40,40),materials
)
cube.geometry.scale(12,12,-12);//在里面看
scene.add(cube)let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);// console.log(camera.position)
});//渲染循环
const clock=new THREE.Clock()
function animate() {controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import _ from 'lodash'let btn=document.getElementById('btn')
btn.onclick=()=>{location.reload();
}//创建场景
const scene = new THREE.Scene();//创建相机
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0,0,30);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);let textureload=new THREE.TextureLoader()
const texture=textureload.load('./img/vr.jpg')
const sphere=new THREE.Mesh(new THREE.SphereGeometry(16,32,32),new THREE.MeshBasicMaterial({map:texture})
)
sphere.geometry.scale(12,12,-12);//在里面看
scene.add(sphere)let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);// console.log(camera.position)
});//渲染循环
const clock=new THREE.Clock()
function animate() {controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();

17-3D看房案例2

18-3D看房3

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import _ from 'lodash'let btn=document.getElementById('btn')
btn.onclick=()=>{location.reload();
}//创建场景
const scene = new THREE.Scene();
const axesHelper = new THREE.AxesHelper( 100 );
scene.add( axesHelper );//创建相机
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0,0,30);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);let textureload=new THREE.TextureLoader()
const texture=textureload.load('./img/vr.jpg')
const sphere=new THREE.Mesh(new THREE.SphereGeometry(16,32,32),new THREE.MeshBasicMaterial({map:texture})
)
sphere.geometry.scale(12,12,-12);//在里面看
scene.add(sphere)//点精灵
const spriteTexture=textureload.load('./img/open.png')
const sprite=new THREE.Sprite(new THREE.SpriteMaterial({map:spriteTexture}))
sprite.scale.set(10,5,1)
sprite.position.set(-70,25,40)
scene.add(sprite)const oTips=document.querySelector('.tip')
const raycaster=new THREE.Raycaster()
const mouse=new THREE.Vector2()let roomType='in'
renderer.domElement.addEventListener('mousemove',(event)=>{mouse.x=(event.clientX/window.innerWidth)*2-1mouse.y=-(event.clientY/window.innerHeight)*2+1raycaster.setFromCamera(mouse,camera)//物体相交const intersects=raycaster.intersectObject(sprite)console.log(intersects,66666)if(intersects.length){const worldVector=new THREE.Vector3(intersects[0].object.position.x,intersects[0].object.position.y,intersects[0].object.position.z,)const dncPostion=worldVector.project(camera)const halfW=window.innerWidth/2const halfH=window.innerHeight/2const left=halfW*dncPostion.x+halfWconst top=halfH*dncPostion.y+halfH-oTips.clientHeight/2-30oTips.style.left=left+'px'oTips.style.top=top+'px'}else{oTips.style.left=0oTips.style.top=0}
})
renderer.domElement.addEventListener('mousedown',(event)=>{mouse.x=(event.clientX/window.innerWidth)*2-1mouse.y=-(event.clientY/window.innerHeight)*2+1raycaster.setFromCamera(mouse,camera)//物体相交const intersects=raycaster.intersectObject(sprite)if(intersects.length){if(roomType==='in'){const changeTexture=textureload.load('./img/vr.jpg')const changeMaterial=new THREE.MeshBasicMaterial({map:changeTexture})sphere.material=changeMaterialsprite.position.set(-70,25,40)roomType='out'}else if(roomType==='out'){const changeTexture=textureload.load('./img/vr2.jpg')const changeMaterial=new THREE.MeshBasicMaterial({map:changeTexture})sphere.material=changeMaterialsprite.position.set(-100,10,80)roomType='in'}}
})let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);// console.log(camera.position)
});//渲染循环
const clock=new THREE.Clock()
function animate() {controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();

19-计算相机方向向量

数学+

jdg 以后认真学 计算

16-计算相机正视的方向向量html

20-向量方法实现物体运动

17-物体使用向量方法运动html

cannon系统学习/10-人物跑动-指定方向添加速度


21-欧拉角解析物体旋转

18-物体选旋转的方法html

欧拉角(Euler)

绕着x轴旋转90°
360°=2Π
180°=П
1°=П/180
90° = П/180
90

rotation

22-四元数解析物体旋转

19-四元数物体旋转.html

四元数(Quaternion)

有公式

const angle=(Math.PI/180)*30;
// const halfAngle=angle/2;
// const sinAngle=Math.sin(halfAngle)
// const cosAngle=Math.cos(halfAngle)
// const quaternion=new THREE.Quaternion(
//   sinAngle*1,
//   sinAngle*0,
//   sinAngle*0,
//   cosAngle
// )
// method 2
const quaternion=new THREE.Quaternion()
const axis=new THREE.Vector3(1,0,0)
quaternion.setFromAxisAngle(axis,angle)
mesh.quaternion.copy(quaternion)

setFromEuler ( efler : Euler ): 欧拉角 to 四元数

23-漫游案例-项目演示搭建

/人物漫游-镜头锁死版/index

person-roam

24-漫游案例-加载3D人物模型


25-漫游案例-添加建筑物
26-漫游案例-编写类执行模型动作


27-漫游案例-键盘控制动作切换
28-控制人物正确朝向
29-控制人物模型运动

30-【物理引擎】认识cannonjs物理引…..

yarn add cannon-es


31-【物理引擎】物理引擎调试工具

yarn add cannon-es-debugger

debug地盘无限大 也可以设置

32-【物理引擎】物理引擎刚体形状全….

33-【物理引擎】不规则形状的应用
34-【物理引擎】物理刚体详解

http://www.webgl3d.cn/pages/e48d3c/


35-【物理引擎】物理刚体碰撞效果
36-【物理引擎】物体碰撞分组问题
37-【物理引擎】施加力的作用

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon-es";
import CannonDebugger from 'cannon-es-debugger'
//创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbfd1e5);//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(2, 3, 10);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);//灯光
const directionLight = new THREE.DirectionalLight(0xffffff, 1); //单独背部 不照到
directionLight.position.set(5, 10, 7.5);
scene.add(directionLight);// 结构和材质组合,生成一个物体
//创建地面
const plane = new THREE.Mesh(new THREE.PlaneGeometry(20, 20),new THREE.MeshStandardMaterial({color: 0x808080,})
);
plane.rotation.x = -Math.PI / 2;scene.add(plane);//创建物理世界
let world = new CANNOU.World();
world.gravity.set(0, -9.8, 0); //世界重力多少
//创建物理材料
const groundMaterial = new CANNOU.Material("groundMaterial");
const sphereMaterial = new CANNOU.Material("sphereMaterial");
const contactMeterial = new CANNOU.ContactMaterial(groundMaterial,sphereMaterial,{restitution: 0.8, //0不弹 1持续}
);
world.addContactMaterial(contactMeterial);//创建物理地面
const groundBody = new CANNOU.Body({mass: 0, //是否有引力  地面默认没shape: new CANNOU.Plane(),material: groundMaterial,
});
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); //position
world.addBody(groundBody);let spheres=[]
const createSphere = (position, direction) => {//创建可视化小球const redius = 1;const sphere = new THREE.Mesh(new THREE.SphereGeometry(redius, 32, 32),new THREE.MeshStandardMaterial({ color: 0xff0000 }));sphere.position.copy(position);scene.add(sphere);//创建物理小球const sphereBody = new CANNOU.Body({mass: 1,material: sphereMaterial,linearDamping: 0.5, //空气阻力});const sphereShape = new CANNOU.Sphere(redius);sphereBody.position.copy(position)sphereBody.addShape(sphereShape);sphereBody.applyLocalForce(direction.scale(600), //用多少力  和球的质量有关massnew CANNOU.Vec3(0, 0, 0) //击中球的上中下位置 0中 10上一点 -10下前后回跑 和台球一样);world.addBody(sphereBody);spheres.push({sphere,sphereBody})
};renderer.domElement.addEventListener("mouseup", (event) => {let mouse = new THREE.Vector2();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;//射线const raycaster = new THREE.Raycaster();raycaster.setFromCamera(mouse, camera);const pos = new THREE.Vector3();pos.copy(raycaster.ray.direction);pos.add(raycaster.ray.origin);const direction = new CANNOU.Vec3(raycaster.ray.direction.x,raycaster.ray.direction.y,raycaster.ray.direction.z);createSphere({x:pos.x,y:pos.y,z:pos.z}, direction);
});const updatePhysic = () => {world.step(1 / 60);spheres.forEach(({sphere,sphereBody})=>{sphere.position.copy(sphereBody.position);sphere.quaternion.copy(sphereBody.quaternion);})};//测试工具
const cannonDebugger=new CannonDebugger(scene,world,{onInit(body,mesh){if(body.shapes[0] instanceof CANNOU.Plane){mesh.scale.set(10,10,1)}},color:0x0000ff
})let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);
});//渲染循环
const clock = new THREE.Clock();
function animate() {cannonDebugger.update()const elapsedTime = clock.getElapsedTime();updatePhysic();controls.update();renderer.render(scene, camera);requestAnimationFrame(animate);
}
animate();

项目

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNOU from "cannon";
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import _, { chain } from 'lodash'
import * as CANNON from 'cannon-es'let btn=document.getElementById('btn')
btn.onclick=()=>{location.reload();
}//创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87ceff);//创建相机
const camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000
);
camera.position.set(0,3,8);
camera.lookAt(0, 0, 0); //改变视野方向
//创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true, //像素变小 锯齿小
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);//灯光
const ambientLight=new THREE.AmbientLight(0xffffff,1)
const directionLight = new THREE.DirectionalLight(0xffffff, 1); //单独背部 不照到
directionLight.castShadow=true
directionLight.position.set(20,20,20);
scene.add(ambientLight,directionLight);const ground=new THREE.Mesh(new THREE.PlaneGeometry(500,500),new THREE.MeshLambertMaterial({color:0xffffff,side:THREE.DoubleSide})
)
ground.receiveShadow=true
ground.rotateX(-Math.PI/2)
scene.add(ground)const getRandomInt=(min,max)=>{return Math.floor(Math.random()*(max-min+1)+min)
}
//创建立方体盒子
const blocks=[]
const createBox=()=>{for(let i=0;i<500;i++){const width=getRandomInt(1,5)const height=getRandomInt(2,6)const depth=getRandomInt(2,4)const x=getRandomInt(-200,200)const z=getRandomInt(-200,200)const y=height/2const mesh=new THREE.Mesh(new THREE.BoxGeometry(width,height,depth),new THREE.MeshLambertMaterial({color:0xff0000}))mesh.position.set(x,y,z)blocks.push(mesh)}
}
createBox()scene.add(...blocks)let modloader=new GLTFLoader()
let process=document.querySelector('.process')
let modelAnimation,player
modloader.load('./mod/girl.glb',(mod)=>{const model=mod.scenemodel.traverse(child=>{if(child.isMesh){child.castShadow=true}})model.scale.set(1,1,1);scene.add(model)player=modelmodelAnimation=new ModelAnimation(model,mod.animations)modelAnimation.start('idle')// const cameraDirectin=new THREE.Vector3()// const playerDirectin=new THREE.Vector3()// camera.getWorldDirection(cameraDirectin)// player.getWorldDirection(playerDirectin)
},(xhr)=>{const percent=(xhr.loaded/xhr.total)*100process.textContent= `${Math.round(percent,2)}%`
},(err)=>{console.log(err.message)
})// 键盘事件
const keyPressed={}
let isJumping=false
window.addEventListener('keydown',(event)=>{const keycode=event.code.toLocaleLowerCase()if(keycode==='space'&& !isJumping){isJumping=truemodelAnimation.updateAction('jump_falling')}keyPressed[keycode]=true
})
window.addEventListener('keyup',(event)=>{const keycode=event.code.toLocaleLowerCase()if(keycode==='space'&& isJumping){setTimeout(() => {isJumping=false}, modelAnimation.getAnimationDuration('jump_falling')*800);}keyPressed[keycode]=false
})
/*更新人物朝向*/
const updateLookAt=()=>{const cameraDirectin=new THREE.Vector3()camera.getWorldDirection(cameraDirectin)const lookAtPostion=new THREE.Vector3()//声明一个速度向量const velocity=new THREE.Vector3(0,0,0.06)const originalLength=velocity.length()if(keyPressed['keyw']){lookAtPostion.set(player.position.x+cameraDirectin.x,player.position.y,player.position.z+cameraDirectin.z)player.lookAt(lookAtPostion)//向前运动代码cameraDirectin.y=0cameraDirectin.normalize()cameraDirectin.setLength(originalLength)player.position.add(cameraDirectin)}else if(keyPressed['keys']){lookAtPostion.set(player.position.x-cameraDirectin.x,player.position.y,player.position.z-cameraDirectin.z)player.lookAt(lookAtPostion)cameraDirectin.y=0cameraDirectin.normalize()cameraDirectin.setLength(originalLength)player.position.sub(cameraDirectin)}else if(keyPressed['keya']){const leftDirection=new THREE.Vector3(-cameraDirectin.z,0,cameraDirectin.x)lookAtPostion.set(player.position.x-leftDirection.x,player.position.y,player.position.z-leftDirection.z)player.lookAt(lookAtPostion)leftDirection.setLength(originalLength)player.position.add(leftDirection.negate())}else if(keyPressed['keyd']){const rightDirection=new THREE.Vector3(cameraDirectin.z,0,-cameraDirectin.x)lookAtPostion.set(player.position.x-rightDirection.x,player.position.y,player.position.z-rightDirection.z)player.lookAt(lookAtPostion)rightDirection.setLength(originalLength)player.position.add(rightDirection.negate())}
}
//更新人物动作
const updateAniamtion=()=>{if(isJumping)returnif((keyPressed['shiftleft']&&keyPressed['keyw'])||(keyPressed['shiftleft']&&keyPressed['keya'])||(keyPressed['shiftleft']&&keyPressed['keys'])||(keyPressed['shiftleft']&&keyPressed['keyd'])){//切换成奔跑动作modelAnimation.updateAction('run')}else if(keyPressed['keyw']||keyPressed['keya']||keyPressed['keys']||keyPressed['keyd']){//切换成走路的动作modelAnimation.updateAction('walk')}else{//切换成站立状态modelAnimation.updateAction('idle')}
}let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; //惯性
controls.addEventListener("change", () => {renderer.render(scene, camera);// console.log(camera.position)
});//渲染循环
const clock=new THREE.Clock()
function animate() {const elapsedTime=clock.getDelta()if(modelAnimation){updateAniamtion()modelAnimation.update(elapsedTime)updateLookAt()};controls.update();renderer.render(scene, camera);window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);class ModelAnimation{constructor(model,animations){this.mixer=new THREE.AnimationMixer(model)// this.animations=model.animationsthis.animations=animationsthis.actionObj={}this.currentAct=nullthis.previousAct=null}start(name){this.actionInit(name)}actionInit(name){this.animations.forEach(clip=>{const action=this.mixer.clipAction(clip)this.actionObj[clip.name]=action})this.currentAct=this.actionObj[name]this.currentAct.play()}updateAction(name,duration=0.2){this.previousAct=this.currentActthis.currentAct=this.actionObj[name]if(this.previousAct!=this.currentAct){this.previousAct.fadeOut(duration)this.currentAct.reset().fadeIn(duration).play()}}update(dt){this.mixer.update(dt)}getAnimationDuration(name){const action=this.actionObj[name]const clip=action.getClip()if(action&&clip){return clip.duration}return 0}
}

gitee 19+ relearn

person-roam

https://gitee.com/wannianqing02/threejs-examples

https://bx2eq6ulg18.feishu.cn/docx/EtsodJe5loGKy2xa0iVcq49WnRb

https://haohuo.jinritemai.com/ecommerce/trade/detail/index.html?id=3705764964951261249&origin_type=604

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/852535.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

命令行下php加载模块

命令行下php加载模块 在命令行下使用 PHP 加载模块,你可以使用 -d 选项来设置 php.ini 中的设置,或者使用 dl() 函数来动态加载 PHP 扩展模块。 例如,如果你想要加载一个名为 my_module.so 的模块,你可以这样做: php -d "extension=my_module.so" script.php &l…

虚拟机配置rsync同步

虚拟机配置rsync同步安装 apt install rsync修改配置文件 vim /etc/rsyncd.confuid = nobody gid = nogroup use chroot = no max connections = 4 pid file = /var/run/rsyncd.pid lock file = /var/run/rsync.lock log file = /var/log/rsyncd.log[html]path = /home/xuxb/ht…

PHP实现开源Consul服务发现与治理

PHP实现开源Consul服务发现与治理 在分布式系统中,服务发现和治理是必不可少的组成部分。其中,consul作为一款服务发现和治理工具,被广泛应用于微服务架构中。本文将介绍如何使用php实现开源consul服务发现与治理。 一、什么是Consul? Consul是一款由HashiCorp公司开发的服…

mysql-搭建主从复制

mysql-搭建主从复制 Master(主):docker run -p 3339:3306 --name master -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 Slave(从):docker run -p 3340:3306 --name slave -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 Master对外映射的端口是3339,Slave对外映射的端口是334…

haproxy配置负载均衡

####安装#####sudo apt updatesudo apt install haproxysudo haproxy -vsudo systemctl status haproxysudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg-org ####配置站点#####vim /etc/haproxy/haproxy.cfg==========================================frontend w…

MUR3060PT-ASEMI快恢复二极管MUR3060PT

MUR3060PT-ASEMI快恢复二极管MUR3060PT编辑:ll MUR3060PT-ASEMI快恢复二极管MUR3060PT 型号:MUR3060PT 品牌:ASEMI 封装:TO-247 特性:快恢复二极管 正向电流:30A 反向耐压:600V 恢复时间:35ns 引脚数量:3 芯片个数:2 芯片尺寸:MIL 浪涌电流:300A 漏电流:10ua 工作…

Jenkins安装ubuntu

ubuntu安装Jenkins apt install fontconfig openjdk-17-jre sudo wget -O /usr/share/keyrings/jenkins-keyring.asc https://pkg.jenkins.io/debian-stable/jenkins.io-2023.keyecho "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" https://pkg.jenkin…

docker更新源

更新docker源修改docker源 vim /etc/docker/daemon.json{"registry-mirrors": ["https://ustc-edu-cn.mirror.aliyuncs.com/","https://ccr.ccs.tencentyun.com/","https://docker.m.daocloud.io/"] }重新加载docker的配置文件 system…

gitlab-runner执行失败

gitlab runner : ERROR: Job failed: prepare environment https://segmentfault.com/a/1190000044719792 查询相关的站点显示错误的原因是由于gitlab runner执行了用户文件夹下的.bash_logout脚本。 一般的解决方法都是将github-runner用户下的.bash_logout中的内容注释掉即可…

gitlab-cid示例1

default: before_script: - echo "start deploy" - echo $CI_COMMIT_REF_NAME # 阶段stages: - install - buildDev - buildTest - buildProd - deployDev - deployTest - deployProd cache: paths: - node_modules/ # 安装依赖install: stage: i…

typora 无限试用去除弹窗修改未激活按钮|Typora实现cnblog文章的推送

typora 无限试用|去除弹窗|修改未激活按钮|Typora实现cnblog文章的推送 改注册表无限试用 start.bat文件 @echo off setlocal enabledelayedexpansion chcp 65001 > nulREM 获取当前日期,格式为MM/dd/yyyy for /f "delims=" %%a in (wmic OS Get localdatetime ^…

微信模板消息

1、注册登陆微信公众平台公众号 2、申请测试账号 3、关注微信公众号、添加测试模板 发消息实现代码package org.example.weixin;import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil;i…