参考资料
知识点
注:基于Three.jsv0.155.0
- 精灵模型Sprite
- 精灵模型标注场景(贴图)
- Sprite模拟下雨、下雪
精灵模型Sprite
Three.js的精灵模型Sprite
和Threejs的网格模型Mesh
一样都是模型对象,父类都是Object3D
,关于精灵模型对象Sprite
的方法和属性除了可以查看文档Sprite,也可以查看父类Object3D
。
Sprite
与矩形平面Mesh
的区别在于,当你旋转三维场景的时候,如果通过相机控件OrbitControls旋转测试,你可以发现Sprite
矩形平面会始终平行于Canvas画布或者说屏幕,而矩形平面Mesh
的姿态角度会跟着旋转,不一定平行于canvas画布。
代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js</title>
</head>
<body>
</body>
<!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 -->
<script type="importmap">
{
"imports": {
"three": "./js/three.module.js",
"three/addons/": "../three.js/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const width = 800
const height = 500
// 场景
const scene = new THREE.Scene();
const texture = new THREE.TextureLoader().load("./img/6.JPG");
// 创建精灵材质对象SpriteMaterial
const spriteMaterial = new THREE.SpriteMaterial({
// color:0x00ffff,//设置颜色
rotation:Math.PI/4,//旋转精灵对象45度,弧度值
map: texture, //设置精灵纹理贴图
transparent:true,//SpriteMaterial默认是true
});
const geometry = new THREE.BoxGeometry(25, 100, 50);
geometry.translate(0, 50, 0);
// 材质
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0.5
});
// mesh顶部中心添加标注,顶部中心坐标是(0,100,0)
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 创建精灵模型对象,不需要几何体geometry参数
const sprite = new THREE.Sprite(spriteMaterial);
// sprite.scale.set(100, 100, 1); //只需要设置x、y两个分量就可以
sprite.scale.set(10, 10, 1);
// sprite.position.set(0,50,0);
sprite.position.set(0, 100 + 10/2, 0);//设置位置,要考虑sprite尺寸影响
scene.add(sprite);
console.log(sprite);
// 环境光
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.2);
scene.add( ambientLight );
// 坐标系
const axes = new THREE.AxesHelper(200);
scene.add(axes);
const group = new THREE.Group();
for (let i = 0; i < 16000; i++) {
// 精灵模型共享材质
const sprite = new THREE.Sprite(spriteMaterial);
group.add(sprite);
sprite.scale.set(1, 1, 1);
// 设置精灵模型位置,在长方体空间上上随机分布
const x = 1000 * (Math.random() - 0.5);
const y = 600 * Math.random();
const z = 1000 * (Math.random() - 0.5);
sprite.position.set(x, y, z)
}
scene.add(group);
const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 1000);
camera.position.set(200, 200, 200);
camera.lookAt(scene.position);
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.render(scene, camera);
document.body.appendChild(renderer.domElement);
const clock = new THREE.Clock();
function loop() {
// loop()两次执行时间间隔
const t = clock.getDelta();
group.children.forEach(sprite => {
// 雨滴的y坐标每次减t*60
sprite.position.y -= t*60;
if (sprite.position.y < 0) {
sprite.position.y = 600;
}
});
requestAnimationFrame(loop);
renderer.render(scene, camera);
}
loop();
// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', () => {
// 因为动画渲染了,所以这里可以省略
// renderer.render(scene, camera);
});
</script>
</html>